diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 7200d49..acb73ce 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -1927,6 +1927,16 @@ int libxl_device_vsnd_destroy(libxl_ctx *ctx, uint32_t domid,
                               const libxl_asyncop_how *ao_how)
                               LIBXL_EXTERNAL_CALLERS_ONLY;
 
+libxl_device_vsnd *libxl_device_vsnd_list(libxl_ctx *ctx,
+                                          uint32_t domid, int *num)
+                                          LIBXL_EXTERNAL_CALLERS_ONLY;
+void libxl_device_vsnd_list_free(libxl_device_vsnd* list, int num)
+                                 LIBXL_EXTERNAL_CALLERS_ONLY;
+int libxl_device_vsnd_getinfo(libxl_ctx *ctx, uint32_t domid,
+                              libxl_device_vsnd *vsnd,
+                              libxl_vsndinfo *vsndlinfo)
+                              LIBXL_EXTERNAL_CALLERS_ONLY;
+
 /* Keyboard */
 int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb,
                          const libxl_asyncop_how *ao_how)
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index fb3e5e8..cd0c06f 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -988,6 +988,25 @@ libxl_vdisplinfo = Struct("vdisplinfo", [
     ("connectors", Array(libxl_connectorinfo, "num_connectors"))
     ], dir=DIR_OUT)
 
+libxl_streaminfo = Struct("streaminfo", [
+    ("req_evtch", integer),
+    ("req_rref", integer)
+    ])
+
+libxl_pcminfo = Struct("pcminfo", [
+    ("streams", Array(libxl_streaminfo, "num_vsnd_streams"))
+    ])
+
+libxl_vsndinfo = Struct("vsndinfo", [
+    ("backend", string),
+    ("backend_id", uint32),
+    ("frontend", string),
+    ("frontend_id", uint32),
+    ("devid", libxl_devid),
+    ("state", integer),
+    ("pcms", Array(libxl_pcminfo, "num_vsnd_pcms"))
+    ])
+
 # NUMA node characteristics: size and free are how much memory it has, and how
 # much of it is free, respectively. dists is an array of distances from this
 # node to each other node.
diff --git a/tools/libxl/libxl_utils.h b/tools/libxl/libxl_utils.h
index 9e743dc..5455752 100644
--- a/tools/libxl/libxl_utils.h
+++ b/tools/libxl/libxl_utils.h
@@ -82,6 +82,9 @@ int libxl_devid_to_device_usbctrl(libxl_ctx *ctx, uint32_t domid,
 int libxl_devid_to_device_vdispl(libxl_ctx *ctx, uint32_t domid,
                                  int devid, libxl_device_vdispl *vdispl);
 
+int libxl_devid_to_device_vsnd(libxl_ctx *ctx, uint32_t domid,
+                               int devid, libxl_device_vsnd *vsnd);
+
 int libxl_ctrlport_to_device_usbdev(libxl_ctx *ctx, uint32_t domid,
                                     int ctrl, int port,
                                     libxl_device_usbdev *usbdev);
diff --git a/tools/libxl/libxl_vsnd.c b/tools/libxl/libxl_vsnd.c
index 26885f9..0e7b29c 100644
--- a/tools/libxl/libxl_vsnd.c
+++ b/tools/libxl/libxl_vsnd.c
@@ -37,20 +37,239 @@ static int libxl__device_from_vsnd(libxl__gc *gc, uint32_t domid,
    return 0;
 }
 
+static int libxl__sample_rates_from_string(libxl__gc *gc, const char *str,
+                                           libxl_vsnd_params *params)
+{
+    char *tmp = libxl__strdup(gc, str);
+
+    params->num_sample_rates = 0;
+    params->sample_rates = NULL;
+
+    char *p = strtok(tmp, " ,");
+
+    while (p != NULL) {
+        params->sample_rates = realloc(params->sample_rates,
+                                       sizeof(*params->sample_rates) *
+                                       (params->num_sample_rates + 1));
+        params->sample_rates[params->num_sample_rates++] = strtoul(p, NULL, 0);
+        p = strtok(NULL, " ,");
+    }
+
+    return 0;
+}
+
+static int libxl__sample_formats_from_string(libxl__gc *gc, const char *str,
+                                             libxl_vsnd_params *params)
+{
+    int rc;
+    char *tmp = libxl__strdup(gc, str);
+
+    params->num_sample_formats = 0;
+    params->sample_formats = NULL;
+
+    char *p = strtok(tmp, " ,");
+
+    while (p != NULL) {
+        params->sample_formats = realloc(params->sample_formats,
+                                         sizeof(*params->sample_formats) *
+                                         (params->num_sample_formats + 1));
+
+        libxl_vsnd_pcm_format format;
+
+        rc = libxl_vsnd_pcm_format_from_string(p, &format);
+        if (rc) return rc;
+
+        params->sample_formats[params->num_sample_formats++] = format;
+        p = strtok(NULL, " ,");
+    }
+
+    return 0;
+}
+
+static int libxl__params_from_xenstore(libxl__gc *gc, const char *path,
+                                       libxl_vsnd_params *params)
+{
+    const char *tmp;
+    int rc;
+
+    rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                GCSPRINTF("%s/"XENSND_FIELD_SAMPLE_RATES,
+                                          path), &tmp);
+    if (rc) return rc;
+
+    if (tmp) {
+        rc = libxl__sample_rates_from_string(gc, tmp, params);
+        if (rc) return rc;
+    }
+
+    rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                GCSPRINTF("%s/"XENSND_FIELD_SAMPLE_FORMATS,
+                                          path), &tmp);
+    if (rc) return rc;
+
+    if (tmp) {
+        rc = libxl__sample_formats_from_string(gc, tmp, params);
+        if (rc) return rc;
+    }
+
+    rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                 GCSPRINTF("%s/"XENSND_FIELD_CHANNELS_MIN,
+                                           path), &tmp);
+    if (rc) return rc;
+
+    if (tmp) {
+        params->channels_min = strtoul(tmp, NULL, 0);
+    }
+
+    rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                 GCSPRINTF("%s/"XENSND_FIELD_CHANNELS_MAX,
+                                           path), &tmp);
+    if (rc) return rc;
+
+    if (tmp) {
+        params->channels_max = strtoul(tmp, NULL, 0);
+    }
+
+    rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                 GCSPRINTF("%s/"XENSND_FIELD_BUFFER_SIZE,
+                                           path), &tmp);
+    if (rc) return rc;
+
+    if (tmp) {
+        params->buffer_size = strtoul(tmp, NULL, 0);
+    }
+
+    return 0;
+}
+
+static int libxl__stream_from_xenstore(libxl__gc *gc, const char *path,
+                                       libxl_vsnd_stream *stream)
+{
+    const char *tmp;
+    int rc;
+
+    rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                GCSPRINTF("%s/"XENSND_FIELD_STREAM_UNIQUE_ID,
+                                          path), &tmp);
+    if (rc) return rc;
+
+    if (tmp) {
+        stream->id = strtoul(tmp, NULL, 0);
+    }
+
+    rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                GCSPRINTF("%s/"XENSND_FIELD_TYPE,
+                                          path), &tmp);
+    if (rc) return rc;
+
+    if (tmp) {
+        libxl_vsnd_stream_type type;
+
+        rc = libxl_vsnd_stream_type_from_string(tmp, &type);
+        if (rc) return rc;
+
+        stream->type = type;
+    }
+
+    rc = libxl__params_from_xenstore(gc, path, &stream->params);
+    if (rc) return rc;
+
+    return 0;
+}
+
+static int libxl__pcm_from_xenstore(libxl__gc *gc, const char *path,
+                                    libxl_vsnd_pcm *pcm)
+{
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+    const char *tmp;
+    int rc;
+
+    pcm->name = xs_read(ctx->xsh, XBT_NULL,
+                        GCSPRINTF("%s/"XENSND_FIELD_DEVICE_NAME, path), NULL);
+
+    rc = libxl__params_from_xenstore(gc, path, &pcm->params);
+
+    pcm->streams = NULL;
+    pcm->num_vsnd_streams = 0;
+
+    do {
+        char *stream_path = GCSPRINTF("%s/%d", path, pcm->num_vsnd_streams);
+
+        rc = libxl__xs_read_checked(gc, XBT_NULL, stream_path, &tmp);
+        if (rc) return rc;
+
+        if (tmp) {
+            pcm->streams = realloc(pcm->streams, sizeof(*pcm->streams) *
+                                   (++pcm->num_vsnd_streams));
+
+            libxl_vsnd_stream_init(&pcm->streams[pcm->num_vsnd_streams - 1]);
+
+            rc = libxl__stream_from_xenstore(gc, stream_path,
+                                             &pcm->streams[pcm->num_vsnd_streams
+                                             - 1]);
+            if (rc) return rc;
+        }
+    } while (tmp);
+
+
+    return 0;
+}
+
 static int libxl__vsnd_from_xenstore(libxl__gc *gc, const char *libxl_path,
                                      libxl_devid devid,
                                      libxl_device_vsnd *vsnd)
 {
-    const char *be_path;
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+    const char *tmp;
+    const char *fe_path;
     int rc;
 
     vsnd->devid = devid;
     rc = libxl__xs_read_mandatory(gc, XBT_NULL,
                                   GCSPRINTF("%s/backend", libxl_path),
-                                  &be_path);
+                                  &tmp);
+    if (rc) return rc;
+
+    rc = libxl__backendpath_parse_domid(gc, tmp, &vsnd->backend_domid);
+    if (rc) return rc;
+
+    rc = libxl__xs_read_mandatory(gc, XBT_NULL,
+                                  GCSPRINTF("%s/frontend", libxl_path),
+                                  &fe_path);
     if (rc) return rc;
 
-    return libxl__backendpath_parse_domid(gc, be_path, &vsnd->backend_domid);
+    vsnd->short_name = xs_read(ctx->xsh, XBT_NULL,
+                               GCSPRINTF("%s/"XENSND_FIELD_VCARD_SHORT_NAME,
+                               fe_path), NULL);
+
+    vsnd->long_name = xs_read(ctx->xsh, XBT_NULL,
+                              GCSPRINTF("%s/"XENSND_FIELD_VCARD_LONG_NAME,
+                              fe_path), NULL);
+
+    rc = libxl__params_from_xenstore(gc, fe_path, &vsnd->params);
+
+    vsnd->pcms = NULL;
+    vsnd->num_vsnd_pcms = 0;
+
+    do {
+        char *pcm_path = GCSPRINTF("%s/%d", fe_path, vsnd->num_vsnd_pcms);
+
+        rc = libxl__xs_read_checked(gc, XBT_NULL, pcm_path, &tmp);
+        if (rc) return rc;
+
+        if (tmp) {
+            vsnd->pcms = realloc(vsnd->pcms, sizeof(*vsnd->pcms) *
+                                 (++vsnd->num_vsnd_pcms));
+
+            libxl_vsnd_pcm_init(&vsnd->pcms[vsnd->num_vsnd_pcms - 1]);
+
+            rc = libxl__pcm_from_xenstore(gc, pcm_path,
+                                          &vsnd->pcms[vsnd->num_vsnd_pcms - 1]);
+            if (rc) return rc;
+        }
+    } while (tmp);
+
+    return 0;
 }
 
 static void libxl__update_config_vsnd(libxl__gc *gc,
@@ -286,10 +505,144 @@ static int libxl__set_xenstore_vsnd(libxl__gc *gc, uint32_t domid,
     return 0;
 }
 
+static int libxl__device_stream_getinfo(libxl__gc *gc, const char *path,
+                                        libxl_vsnd_pcm* pcm,
+                                        libxl_pcminfo *info)
+{
+    const char *tmp;
+    int i;
+    int rc;
+
+    info->num_vsnd_streams = pcm->num_vsnd_streams;
+    info->streams = malloc(sizeof(*info->streams) * info->num_vsnd_streams);
+
+    for (i = 0; i < info->num_vsnd_streams; i++)
+    {
+        libxl_streaminfo_init(&info->streams[i]);
+
+        rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                    GCSPRINTF("%s/%d/"XENSND_FIELD_RING_REF,
+                                    path, i), &tmp);
+        if (rc) return rc;
+
+        info->streams[i].req_rref = tmp ? strtoul(tmp, NULL, 10) : -1;
+
+        rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                    GCSPRINTF("%s/%d/"XENSND_FIELD_EVT_CHNL,
+                                    path, i), &tmp);
+        if (rc) return rc;
+
+        info->streams[i].req_evtch = tmp ? strtoul(tmp, NULL, 10) : -1;
+    }
+
+    return 0;
+}
+
+static int libxl__device_pcm_getinfo(libxl__gc *gc, const char *path,
+                                     libxl_device_vsnd *vsnd,
+                                     libxl_vsndinfo *info)
+{
+    int i;
+    int rc;
+
+    info->num_vsnd_pcms = vsnd->num_vsnd_pcms;
+    info->pcms = malloc(sizeof(*info->pcms) * info->num_vsnd_pcms);
+
+    for (i = 0; i < info->num_vsnd_pcms; i++)
+    {
+        libxl_pcminfo_init(&info->pcms[i]);
+
+        rc = libxl__device_stream_getinfo(gc, GCSPRINTF("%s/%d", path, i),
+                                          &vsnd->pcms[i], &info->pcms[i]);
+        if (rc) return rc;
+    }
+
+    return 0;
+}
+
+int libxl_device_vsnd_getinfo(libxl_ctx *ctx, uint32_t domid,
+                              libxl_device_vsnd *vsnd,
+                              libxl_vsndinfo *info)
+{
+    GC_INIT(ctx);
+    char *libxl_path, *dompath, *devpath;
+    const char *val;
+    int rc;
+
+    libxl_vsndinfo_init(info);
+    dompath = libxl__xs_get_dompath(gc, domid);
+    info->devid = vsnd->devid;
+
+    devpath = GCSPRINTF("%s/device/%s/%d", dompath, libxl__vsnd_devtype.entry,
+                                           info->devid);
+    libxl_path = GCSPRINTF("%s/device/%s/%d",
+                           libxl__xs_libxl_path(gc, domid),
+                           libxl__vsnd_devtype.entry, info->devid);
+
+    info->backend = xs_read(ctx->xsh, XBT_NULL,
+                            GCSPRINTF("%s/backend", libxl_path), NULL);
+
+    rc = libxl__backendpath_parse_domid(gc, info->backend, &info->backend_id);
+    if (rc) goto out;
+
+    val = xs_read(ctx->xsh, XBT_NULL, GCSPRINTF("%s/state", devpath), NULL);
+
+    info->state = val ? strtoul(val, NULL, 10) : -1;
+
+    info->frontend = xs_read(ctx->xsh, XBT_NULL,
+                             GCSPRINTF("%s/frontend", libxl_path), NULL);
+
+    info->frontend_id = domid;
+
+    rc = libxl__device_pcm_getinfo(gc, devpath, vsnd, info);
+    if (rc) goto out;
+
+    rc = 0;
+
+out:
+     GC_FREE;
+     return rc;
+}
+
+int libxl_devid_to_device_vsnd(libxl_ctx *ctx, uint32_t domid,
+                               int devid, libxl_device_vsnd *vsnd)
+{
+    GC_INIT(ctx);
+
+    libxl_device_vsnd *vsnds = NULL;
+    int n, i;
+    int rc;
+
+    libxl_device_vsnd_init(vsnd);
+
+    vsnds = libxl__device_list(gc, &libxl__vsnd_devtype, domid, &n);
+
+    if (!vsnds) { rc = ERROR_NOTFOUND; goto out; }
+
+    for (i = 0; i < n; ++i) {
+        if (devid == vsnds[i].devid) {
+            libxl_device_vsnd_copy(ctx, vsnd, &vsnds[i]);
+            rc = 0;
+            goto out;
+        }
+    }
+
+    rc = ERROR_NOTFOUND;
+
+out:
+
+    if (vsnds)
+        libxl__device_list_free(&libxl__vsnd_devtype, vsnds, n);
+
+    GC_FREE;
+    return rc;
+}
+
 LIBXL_DEFINE_DEVICE_ADD(vsnd)
 static LIBXL_DEFINE_DEVICES_ADD(vsnd)
 LIBXL_DEFINE_DEVICE_REMOVE(vsnd)
 static LIBXL_DEFINE_UPDATE_DEVID(vsnd, "vsnd")
+LIBXL_DEFINE_DEVICE_LIST(vsnd)
 
 DEFINE_DEVICE_TYPE_STRUCT(vsnd,
     .update_config = (device_update_config_fn_t) libxl__update_config_vsnd,
