diff --git a/tools/xl/Makefile b/tools/xl/Makefile
index d742e96a5b..122dfb9346 100644
--- a/tools/xl/Makefile
+++ b/tools/xl/Makefile
@@ -32,7 +32,7 @@ $(XL_OBJS): CFLAGS += -include $(XEN_ROOT)/tools/config.h # libxl_json.h needs i
 all: xl
 
 xl: $(XL_OBJS)
-	$(CC) $(LDFLAGS) -o $@ $(XL_OBJS) $(LDLIBS_libxenutil) $(LDLIBS_libxenlight) $(LDLIBS_libxentoollog) -lyajl $(APPEND_LDFLAGS)
+	$(CC) $(LDFLAGS) -o $@ $(XL_OBJS) $(LDLIBS_libxenutil) $(LDLIBS_libxenlight) $(LDLIBS_libxentoollog) $(LDLIBS_libxenstore) $(LDLIBS_libxengnttab) -lyajl $(APPEND_LDFLAGS)
 
 .PHONY: install
 install: all
diff --git a/tools/xl/xl_cmdtable.c b/tools/xl/xl_cmdtable.c
index 62bdb2aeaa..2531e8517b 100644
--- a/tools/xl/xl_cmdtable.c
+++ b/tools/xl/xl_cmdtable.c
@@ -635,7 +635,7 @@ const struct cmd_spec cmd_table[] = {
     { "dt-overlay",
       &main_dt_overlay, 0, 1,
       "Add/Remove a device tree overlay",
-      "add/remove <.dtbo>"
+      "add/remove <.dtbo> domain_id -e[expert_mode]",
       "-h print this help\n"
     },
 #endif
diff --git a/tools/xl/xl_vmcontrol.c b/tools/xl/xl_vmcontrol.c
index 9674383ec3..2bf76dd389 100644
--- a/tools/xl/xl_vmcontrol.c
+++ b/tools/xl/xl_vmcontrol.c
@@ -16,6 +16,7 @@
 #include <inttypes.h>
 #include <limits.h>
 #include <stdlib.h>
+#include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/utsname.h>
@@ -29,6 +30,8 @@
 #include "xl.h"
 #include "xl_utils.h"
 #include "xl_parse.h"
+#include <xenstore.h>
+#include <xengnttab.h>
 
 static int fd_lock = -1;
 
@@ -1266,6 +1269,335 @@ int main_create(int argc, char **argv)
 }
 
 #ifdef LIBXL_HAVE_DT_OVERLAY
+static int copy_overlay_to_domU(uint32_t domain_id, void *overlay_dt_domU,
+                                uint32_t overlay_dt_size, uint32_t *grant_ref,
+                                uint32_t num_pages)
+{
+    void *buffer = NULL;
+    xengnttab_handle *gnttab = xengnttab_open(NULL, 0);
+
+    if (!gnttab) {
+        fprintf(stderr,"opening gnttab failed for domain %d\n", domain_id);
+        return -1;
+    }
+
+    buffer = xengnttab_map_domain_grant_refs(gnttab, num_pages, domain_id,
+                                             grant_ref, PROT_READ|PROT_WRITE);
+
+    if (buffer == NULL) {
+        fprintf(stderr, "Getting the buffer failed for grant_refs\n");
+
+        return -1;
+    }
+
+    /* buffer is contiguous allocated. */
+    memcpy(buffer, overlay_dt_domU, overlay_dt_size);
+
+    xengnttab_unmap(gnttab, buffer, num_pages);
+
+    return 0;
+}
+
+static bool wait_for_status(struct xs_handle *xs, int fd, char *status_path,
+                            const char *status)
+{
+    unsigned int num_strings;
+    char *buf = NULL;
+    char **vec = NULL;
+    bool ret = false;
+    unsigned int len;
+    int rc = 0;
+    fd_set set;
+
+    while (1)
+    {
+        FD_ZERO(&set);
+        FD_SET(fd, &set);
+
+        rc = select(fd + 1, &set, NULL, NULL, NULL);
+        /* Poll for data: Blocking. */
+        if (rc <= 0)
+            break;
+
+        if (FD_ISSET(fd, &set)) {
+            /*
+             * num_strings will be set to the number of elements in vec
+             * (2 - the watched path and the overlay_watch)
+             */
+            vec = xs_read_watch(xs, &num_strings);
+            if (!vec) {
+                break;
+            }
+
+            /* do a read. */
+            buf = xs_read(xs, XBT_NULL, status_path, &len);
+            if (buf) {
+                if (!strcmp(buf, status)) {
+                    ret = true;
+                    break;
+                }
+            }
+        }
+    }
+
+    free(vec);
+    free(buf);
+
+    return ret;
+}
+
+static bool write_overlay_size(struct xs_handle *xs, uint32_t overlay_size,
+                               char *path)
+{
+    xs_transaction_t xs_trans = XBT_NULL;
+    char buf[128];
+    char ref[16];
+
+retry_transaction:
+    xs_trans = xs_transaction_start(xs);
+    if (!xs_trans)
+        return false;
+
+    snprintf(ref, sizeof(ref), "%u", overlay_size);
+    snprintf(buf, sizeof(buf), "%s/overlay-size", path);
+
+    if (!xs_write(xs, xs_trans, buf, ref, strlen(ref)))
+        return false;
+
+    if (!xs_transaction_end(xs, xs_trans, 0)) {
+        if (errno == EAGAIN)
+            goto retry_transaction;
+        else
+            return false;
+    }
+
+    return true;
+}
+
+static bool write_status(struct xs_handle *xs, char *status, char *status_path)
+{
+    xs_transaction_t xs_trans = XBT_NULL;
+
+retry_transaction:
+    xs_trans = xs_transaction_start(xs);
+    if (!xs_trans)
+        return false;
+
+    if (!xs_write(xs, xs_trans, status_path, status, strlen(status)))
+        return false;
+
+    if (!xs_transaction_end(xs, xs_trans, 0)) {
+        if (errno == EAGAIN)
+            goto retry_transaction;
+        else
+            return false;
+    }
+
+    return true;
+}
+
+static uint32_t *get_page_ref(struct xs_handle *xs, const char *xs_path,
+                              uint32_t num_pages)
+{
+    char buf[128];
+    uint32_t *ref = NULL;
+    char *data;
+    char temp[16] = { };
+    unsigned int len;
+    int i = 0;
+    int j = 0;
+    int start_ind = 0;
+
+    snprintf(buf, sizeof(buf), "%s/page-ref", xs_path);
+
+    /* do a read. */
+    data = xs_read(xs, XBT_NULL, buf, &len);
+
+    if (data) {
+        /* Caller will free this. */
+        ref = (uint32_t *)calloc(num_pages, sizeof(uint32_t));
+
+        for (i = 0; data[i] != '\0'; i++) {
+            if (data[i] == ',') {
+                /* Next page_ref data. */
+                memset(temp, '\0', sizeof(temp));
+
+                /* Copy the data between previous ',' to current. */
+                memcpy(temp, &data[start_ind], i - start_ind);
+
+                /* Convert to int. */
+                ref[j] = atoi(temp);
+                start_ind = i + 1;
+                j++;
+            }
+
+            if (j == num_pages)
+                break;
+        }
+    }
+
+    if (j != num_pages) {
+        fprintf(stderr, "Number of page_refs are not equal to num_pages\n");
+        free(ref);
+        ref = NULL;
+    }
+
+    free(data);
+    return ref;
+}
+
+static uint32_t get_num_pages(struct xs_handle *xs, const char *xs_path)
+{
+    char buf[128];
+    char *ref;
+    unsigned int len;
+    uint32_t num_pages = 0;
+
+    snprintf(buf, sizeof(buf), "%s/num-pages", xs_path);
+
+    /* do a read. */
+    ref = xs_read(xs, XBT_NULL, buf, &len);
+
+    if (ref)
+        num_pages = atoi(ref);
+
+    free(ref);
+
+    return num_pages;
+}
+
+static int share_overlay_with_domu(void *overlay_dt_domU, int overlay_dt_size,
+                                   int domain_id)
+{
+    struct xs_handle *xs = NULL;
+    char *path = NULL;
+    char receiver_status_path[64] = { };
+    char sender_status_path[64] = { };
+    int fd = 0;
+    int err;
+    uint32_t num_pages= 1;
+    uint32_t *page_ref = NULL;
+
+    /* XS_watch part. */
+    /* Open a connection to the xenstore. */
+    xs = xs_open(0);
+    if (xs == NULL) {
+        fprintf(stderr, "Deamon open for domain%d failed\n", domain_id);
+        err = ERROR_FAIL;
+        goto out;
+    }
+
+    /* Get the local domain path */
+    path = xs_get_domain_path(xs, domain_id);
+    if (path == NULL) {
+        fprintf(stderr, "Getting domain%d path failed\n", domain_id);
+        err = ERROR_FAIL;
+        goto out;
+    }
+
+    /* Make space for our node on the path */
+    path = realloc(path, strlen(path) + strlen("/data/overlay") + 1);
+    if (path == NULL) {
+        fprintf(stderr, "Path allocation failed\n");
+        err = ERROR_NOMEM;
+        goto out;
+    }
+
+    strcat(path, "/data/overlay");
+    strcpy(receiver_status_path, path);
+    strcat(receiver_status_path, "/receiver-status");
+
+    /*
+     * Watch a node for changes (poll on fd to detect).
+     * When the node (or any child) changes, fd will become readable.
+     */
+    err = xs_watch(xs, receiver_status_path, "overlay_watch");
+    if (!err) {
+        fprintf(stderr, "Creating watch failed\n");
+        err = ERROR_FAIL;
+        goto out;
+    }
+
+    /*
+     * We are notified of read availability on the watch via the
+     * file descriptor.
+     */
+    fd = xs_fileno(xs);
+
+    /* Wait for "waiting" status from other domain. */
+    if (!wait_for_status(xs, fd, receiver_status_path, "waiting")) {
+        err = ERROR_NOT_READY;
+        goto out;
+    }
+
+    /* Share the dtb size with domain. */
+    if (!write_overlay_size(xs, overlay_dt_size, path)) {
+        err = ERROR_FAIL;
+        fprintf(stderr,"Writing page ref failed\n");
+        goto out;
+    }
+
+    strcpy(sender_status_path, path);
+    strcat(sender_status_path, "/sender-status");
+
+    /* Write the status "ready". */
+    if (!write_status(xs, "ready", sender_status_path)) {
+        err = ERROR_FAIL;
+        fprintf(stderr,"Writing status ready failed\n");
+        goto out;
+    }
+
+    /* Wait for "page_ref" status from other domain. */
+    if (!wait_for_status(xs, fd, receiver_status_path, "page_ref")) {
+        err = ERROR_NOT_READY;
+        goto out;
+    }
+
+    num_pages = get_num_pages(xs, path);
+    if (num_pages == 0) {
+        fprintf(stderr, "no pages allocated\n");
+        err = ERROR_FAIL;
+        goto out;
+    }
+
+    page_ref = get_page_ref(xs, path, num_pages);
+    if (page_ref == NULL) {
+        fprintf(stderr,"page ref is null.\n");
+        err = ERROR_FAIL;
+        goto out;
+    }
+
+    if (copy_overlay_to_domU(domain_id, overlay_dt_domU, overlay_dt_size,
+                             page_ref, num_pages)) {
+        fprintf(stderr,"Copy overlay failed\n");
+        err = ERROR_FAIL;
+        goto out;
+    }
+
+    /* Write the status "done". */
+    if (!write_status(xs, "done", sender_status_path)) {
+        fprintf(stderr,"Writing status DONE failed\n");
+        err = ERROR_FAIL;
+        goto out;
+    }
+
+/* Cleanup */
+out:
+    if (xs) {
+        close(fd);
+        xs_unwatch(xs, path, "overlay_watch");
+        xs_close(xs);
+    }
+
+    if (path)
+        free(path);
+
+    if (page_ref)
+        free(page_ref);
+
+    return err;
+}
+
 int main_dt_overlay(int argc, char **argv)
 {
     const char *overlay_ops = NULL;
@@ -1339,11 +1671,16 @@ int main_dt_overlay(int argc, char **argv)
     rc = libxl_dt_overlay(ctx, domain_id, overlay_dtb, overlay_dtb_size, op,
                           auto_mode, domain_mapping);
 
-    free(overlay_dtb);
-
-    if (rc)
+    if (rc) {
+        free(overlay_dtb);
         return EXIT_FAILURE;
+    }
+
+    if (domain_id && auto_mode && (op == LIBXL_DT_OVERLAY_ADD))
+        rc = share_overlay_with_domu(overlay_dtb, overlay_dtb_size,
+                                     domain_id);
 
+    free(overlay_dtb);
     return rc;
 }
 #endif
