diff --git a/qemud/qemud.c b/qemud/qemud.c
index 9da27d2..3020d81 100644
--- a/qemud/qemud.c
+++ b/qemud/qemud.c
@@ -723,12 +723,12 @@ static struct qemud_server *qemudInitialize(int sigread) {
 
     server->sigread = sigread;
 
-    __virEventRegisterImpl(virEventAddHandleImpl,
-                           virEventUpdateHandleImpl,
-                           virEventRemoveHandleImpl,
-                           virEventAddTimeoutImpl,
-                           virEventUpdateTimeoutImpl,
-                           virEventRemoveTimeoutImpl);
+    virEventRegisterImpl(virEventAddHandleImpl,
+                         virEventUpdateHandleImpl,
+                         virEventRemoveHandleImpl,
+                         virEventAddTimeoutImpl,
+                         virEventUpdateTimeoutImpl,
+                         virEventRemoveTimeoutImpl);
 
     virStateInitialize();
 
@@ -1105,7 +1105,12 @@ static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket
     client->auth = sock->auth;
     memcpy (&client->addr, &addr, sizeof addr);
     client->addrlen = addrlen;
+    client->server = server;
 
+    if(VIR_ALLOC(client->domainEventCallbacks)<0) {
+        qemudLog(QEMUD_ERR, _("Error allocating domainEventCallbacks: %s"), strerror(errno));
+        goto cleanup;
+    }
 #if HAVE_POLKIT
     /* Only do policy checks for non-root - allow root user
        through with no checks, as a fail-safe - root can easily
@@ -1199,6 +1204,15 @@ static void qemudDispatchClientFailure(struct qemud_server *server, struct qemud
 
     virEventRemoveHandleImpl(client->fd);
 
+    /* Deregister event delivery callback */
+    if(client->conn) {
+        qemudDebug("Deregistering to relay remote events");
+        virConnectDomainEventDeregister(client->conn, remoteRelayDomainEvent);
+    }
+
+    /* Free domain callback list */
+    __virDomainEventCallbackListFree(client->domainEventCallbacks);
+
     if (client->conn)
         virConnectClose(client->conn);
 
@@ -1503,7 +1517,7 @@ static int qemudClientWrite(struct qemud_server *server,
 }
 
 
-static void qemudDispatchClientWrite(struct qemud_server *server, struct qemud_client *client) {
+void qemudDispatchClientWrite(struct qemud_server *server, struct qemud_client *client) {
     switch (client->mode) {
     case QEMUD_MODE_TX_PACKET: {
         if (qemudClientWrite(server, client) < 0)
diff --git a/qemud/qemud.h b/qemud/qemud.h
index 91cb939..2fb3ca9 100644
--- a/qemud/qemud.h
+++ b/qemud/qemud.h
@@ -132,6 +132,12 @@ struct qemud_client {
      */
     virConnectPtr conn;
 
+    /* This is the list of remote callbacks registered */
+    virDomainEventCallbackListPtr domainEventCallbacks;
+
+    /* back-pointer to our server */
+    struct qemud_server *server;
+
     struct qemud_client *next;
 };
 
@@ -179,8 +185,16 @@ void qemudLog(int priority, const char *fmt, ...)
 void remoteDispatchClientRequest (struct qemud_server *server,
                                   struct qemud_client *client);
 
+void qemudDispatchClientWrite(struct qemud_server *server,
+                             struct qemud_client *client);
+
 #if HAVE_POLKIT
 int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid);
 #endif
 
+int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED,
+                            virDomainPtr dom,
+                            int event,
+                            void *opaque);
+
 #endif
diff --git a/qemud/remote.c b/qemud/remote.c
index 72e064e..eeed5fd 100644
--- a/qemud/remote.c
+++ b/qemud/remote.c
@@ -75,6 +75,13 @@ typedef int (*dispatch_fn) (struct qemud_server *server,
                             char *args,
                             char *ret);
 
+/* Prototypes */
+static void
+remoteDispatchDomainEventSend (struct qemud_client *client,
+                               virDomainPtr dom,
+                               virDomainEventType event,
+                               virDomainEventCallbackPtr callback);
+
 /* This function gets called from qemud when it detects an incoming
  * remote protocol message.  At this point, client->buffer contains
  * the full call message (including length word which we skip).
@@ -405,6 +412,24 @@ remoteDispatchError (struct qemud_client *client,
     remoteDispatchSendError (client, req, VIR_ERR_RPC, msg);
 }
 
+int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED,
+                                   virDomainPtr dom,
+                                   int event,
+                                   void *opaque)
+{
+    int i;
+    struct qemud_client *c = opaque;
+    REMOTE_DEBUG("Relaying domain event %d", event);
+
+    if(c && c->domainEventCallbacks) {
+        for(i=0; i < c->domainEventCallbacks->count; i++) {
+            remoteDispatchDomainEventSend (c, dom, event,
+                                           c->domainEventCallbacks->callbacks[i]);
+            qemudDispatchClientWrite(c->server,c);
+        }
+    }
+    return 0;
+}
 
 
 /*----- Functions. -----*/
@@ -3620,6 +3645,139 @@ remoteDispatchStorageVolLookupByPath (struct qemud_server *server ATTRIBUTE_UNUS
 }
 
 
+/**************************
+ * Async Events
+ **************************/
+static int remoteDispatchDomainEvent (struct qemud_server *server ATTRIBUTE_UNUSED,
+                                      struct qemud_client *client ATTRIBUTE_UNUSED,
+                                      remote_message_header *req ATTRIBUTE_UNUSED,
+                                      void *args ATTRIBUTE_UNUSED,
+                                      remote_domain_event_ret *ret ATTRIBUTE_UNUSED)
+{
+    /* This call gets dispatched from a client call.
+     * This does not make sense, as this should not be intiated
+     * from the client side in generated code.
+     */
+     return -1;
+}
+
+/***************************
+ * Register / deregister events
+ ***************************/
+static int remoteDispatchDomainEventsRegister (struct qemud_server *server ATTRIBUTE_UNUSED,
+                                               struct qemud_client *client,
+                                               remote_message_header *req ATTRIBUTE_UNUSED,
+                                               remote_domain_events_register_args *args ATTRIBUTE_UNUSED,
+                                               void *ret ATTRIBUTE_UNUSED)
+{
+    CHECK_CONN(client);
+
+    if( __virDomainEventCallbackListAdd(client->conn, client->domainEventCallbacks,
+                                     (virConnectDomainEventCallback)args->callback,
+                                     (void *)args->user_data) < 0 ) {
+        REMOTE_DEBUG("%s","Error adding event callback");
+        return -1;
+    }
+
+    /* Register event delivery callback
+     * This is redundant if already registered for this client
+     */
+    REMOTE_DEBUG("%s","Registering to relay remote events");
+    virConnectDomainEventRegister(client->conn, remoteRelayDomainEvent, client);
+
+    return 0;
+}
+
+static int remoteDispatchDomainEventsDeregister (struct qemud_server *server ATTRIBUTE_UNUSED,
+                                                 struct qemud_client *client,
+                                                 remote_message_header *req ATTRIBUTE_UNUSED,
+                                                 remote_domain_events_deregister_args *args ATTRIBUTE_UNUSED,
+                                                 void *ret ATTRIBUTE_UNUSED)
+{
+    CHECK_CONN(client);
+
+    if( __virDomainEventCallbackListRemove(client->conn, client->domainEventCallbacks,
+                                         (virConnectDomainEventCallback)args->callback) < 0 ) {
+        REMOTE_DEBUG("%s","WARNING: Could not remove event callback from list");
+    }
+
+    /* Deregister event delivery callback */
+    REMOTE_DEBUG("%s","Deregistering to relay remote events");
+    virConnectDomainEventDeregister(client->conn, remoteRelayDomainEvent);
+
+    return 0;
+}
+
+static void
+remoteDispatchDomainEventSend (struct qemud_client *client,
+                         virDomainPtr dom,
+                         virDomainEventType event,
+                         virDomainEventCallbackPtr callback)
+{
+    remote_message_header rep;
+    XDR xdr;
+    int len;
+    remote_domain_event_ret data;
+
+    if(!client) {
+        remoteDispatchError (client, NULL, "%s", _("Invalid Client"));
+        return;
+    }
+
+    rep.prog = REMOTE_PROGRAM;
+    rep.vers = REMOTE_PROTOCOL_VERSION;
+    rep.proc = REMOTE_PROC_DOMAIN_EVENT;
+    rep.direction = REMOTE_MESSAGE;
+    rep.serial = 1;
+    rep.status = REMOTE_OK;
+
+    /* Serialise the return header and event. */
+    xdrmem_create (&xdr, client->buffer, sizeof client->buffer, XDR_ENCODE);
+
+    len = 0; /* We'll come back and write this later. */
+    if (!xdr_int (&xdr, &len)) {
+        remoteDispatchError (client, NULL, "%s", _("xdr_int failed (1)"));
+        xdr_destroy (&xdr);
+        return;
+    }
+
+    if (!xdr_remote_message_header (&xdr, &rep)) {
+        xdr_destroy (&xdr);
+        return;
+    }
+
+    /* build return data */
+    make_nonnull_domain (&data.dom, dom);
+    data.event = (int) event;
+    data.callback = (unsigned long) callback->cb;
+    data.user_data = (unsigned long) callback->opaque;
+
+    if (!xdr_remote_domain_event_ret(&xdr, &data)) {
+        remoteDispatchError (client, NULL, "%s", _("serialise return struct"));
+        xdr_destroy (&xdr);
+        return;
+    }
+
+    len = xdr_getpos (&xdr);
+    if (xdr_setpos (&xdr, 0) == 0) {
+        remoteDispatchError (client, NULL, "%s", _("xdr_setpos failed"));
+        xdr_destroy (&xdr);
+        return;
+    }
+
+    if (!xdr_int (&xdr, &len)) {
+        remoteDispatchError (client, NULL, "%s", _("xdr_int failed (2)"));
+        xdr_destroy (&xdr);
+        return;
+    }
+
+    xdr_destroy (&xdr);
+
+    /* Send it. */
+    client->mode = QEMUD_MODE_TX_PACKET;
+    client->bufferLength = len;
+    client->bufferOffset = 0;
+}
 /*----- Helpers. -----*/
 
 /* get_nonnull_domain and get_nonnull_network turn an on-wire
