diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 49b2c63..2d52435 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -138,7 +138,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
 			libxl_dom_suspend.o libxl_dom_save.o libxl_usb.o \
 			libxl_vtpm.o libxl_nic.o libxl_disk.o libxl_console.o \
 			libxl_cpupool.o libxl_mem.o libxl_sched.o libxl_tmem.o \
-			libxl_9pfs.o libxl_domain.o libxl_vdispl.o \
+			libxl_9pfs.o libxl_domain.o libxl_vdispl.o libxl_vsnd.o \
                         $(LIBXL_OBJS-y)
 LIBXL_OBJS += libxl_genid.o
 LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 7d853ca..7200d49 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -1913,6 +1913,20 @@ int libxl_device_vdispl_getinfo(libxl_ctx *ctx, uint32_t domid,
                                 libxl_vdisplinfo *vdisplinfo)
                                 LIBXL_EXTERNAL_CALLERS_ONLY;
 
+/* Virtual sounds */
+int libxl_device_vsnd_add(libxl_ctx *ctx, uint32_t domid,
+                          libxl_device_vsnd *vsnd,
+                          const libxl_asyncop_how *ao_how)
+                          LIBXL_EXTERNAL_CALLERS_ONLY;
+int libxl_device_vsnd_remove(libxl_ctx *ctx, uint32_t domid,
+                             libxl_device_vsnd *vsnd,
+                             const libxl_asyncop_how *ao_how)
+                             LIBXL_EXTERNAL_CALLERS_ONLY;
+int libxl_device_vsnd_destroy(libxl_ctx *ctx, uint32_t domid,
+                              libxl_device_vsnd *vsnd,
+                              const libxl_asyncop_how *ao_how)
+                              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_create.c b/tools/libxl/libxl_create.c
index 0ef54d2..f813114 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -1449,6 +1449,7 @@ const struct libxl_device_type *device_type_tbl[] = {
     &libxl__pcidev_devtype,
     &libxl__dtdev_devtype,
     &libxl__vdispl_devtype,
+    &libxl__vsnd_devtype,
     NULL
 };
 
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 8b71517..6b403dc 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -3575,6 +3575,7 @@ extern const struct libxl_device_type libxl__usbdev_devtype;
 extern const struct libxl_device_type libxl__pcidev_devtype;
 extern const struct libxl_device_type libxl__vdispl_devtype;
 extern const struct libxl_device_type libxl__p9_devtype;
+extern const struct libxl_device_type libxl__vsnd_devtype;
 
 extern const struct libxl_device_type *device_type_tbl[];
 
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 756e120..fb3e5e8 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -793,6 +793,69 @@ libxl_device_vdispl = Struct("device_vdispl", [
     ("connectors", Array(libxl_connector_param, "num_connectors"))
     ])
 
+libxl_vsnd_pcm_format = Enumeration("vsnd_pcm_format", [
+    (1,  "S8"),
+    (2,  "U8"),
+    (3,  "S16_LE"),
+    (4,  "S16_BE"),
+    (5,  "U16_LE"),
+    (6,  "U16_BE"),
+    (7,  "S24_LE"),
+    (8,  "S24_BE"),
+    (9,  "U24_LE"),
+    (10, "U24_BE"),
+    (11, "S32_LE"),
+    (12, "S32_BE"),
+    (13, "U32_LE"),
+    (14, "U32_BE"),
+    (15, "F32_LE"),
+    (16, "F32_BE"),
+    (17, "F64_LE"),
+    (18, "F64_BE"),
+    (19, "IEC958_SUBFRAME_LE"),
+    (20, "IEC958_SUBFRAME_BE"),
+    (21, "MU_LAW"),
+    (22, "A_LAW"),
+    (23, "IMA_ADPCM"),
+    (24, "MPEG"),
+    (25, "GSM")
+    ])
+
+libxl_vsnd_params = Struct("vsnd_params", [
+    ("sample_rates", Array(uint32, "num_sample_rates")),
+    ("sample_formats", Array(libxl_vsnd_pcm_format, "num_sample_formats")),
+    ("channels_min", uint32),
+    ("channels_max", uint32),
+    ("buffer_size", uint32)
+    ])
+
+libxl_vsnd_stream_type = Enumeration("vsnd_stream_type", [
+    (1, "P"),
+    (2, "C")
+    ])
+
+libxl_vsnd_stream = Struct("vsnd_stream", [
+    ("id", uint32),
+    ("type", libxl_vsnd_stream_type),
+    ("params", libxl_vsnd_params)
+    ])
+
+libxl_vsnd_pcm = Struct("vsnd_pcm", [
+    ("name", string),
+    ("params", libxl_vsnd_params),
+    ("streams", Array(libxl_vsnd_stream, "num_vsnd_streams"))
+    ])
+
+libxl_device_vsnd = Struct("device_vsnd", [
+    ("backend_domid", libxl_domid),
+    ("backend_domname", string),
+    ("devid", libxl_devid),
+    ("short_name", string),
+    ("long_name", string),
+    ("params", libxl_vsnd_params),
+    ("pcms", Array(libxl_vsnd_pcm, "num_vsnd_pcms"))
+    ])
+
 libxl_domain_config = Struct("domain_config", [
     ("c_info", libxl_domain_create_info),
     ("b_info", libxl_domain_build_info),
@@ -807,6 +870,7 @@ libxl_domain_config = Struct("domain_config", [
     ("vtpms", Array(libxl_device_vtpm, "num_vtpms")),
     ("p9s", Array(libxl_device_p9, "num_p9s")),
     ("vdispls", Array(libxl_device_vdispl, "num_vdispls")),
+    ("vsnds", Array(libxl_device_vsnd, "num_vsnds")),
     # a channel manifests as a console with a name,
     # see docs/misc/channels.txt
     ("channels", Array(libxl_device_channel, "num_channels")),
diff --git a/tools/libxl/libxl_types_internal.idl b/tools/libxl/libxl_types_internal.idl
index 673a6d5..7898dae 100644
--- a/tools/libxl/libxl_types_internal.idl
+++ b/tools/libxl/libxl_types_internal.idl
@@ -27,6 +27,7 @@ libxl__device_kind = Enumeration("device_kind", [
     (10, "QUSB"),
     (11, "9PFS"),
     (12, "VDISPL"),
+    (13, "VSND")
     ])
 
 libxl__console_backend = Enumeration("console_backend", [
diff --git a/tools/libxl/libxl_vsnd.c b/tools/libxl/libxl_vsnd.c
new file mode 100644
index 0000000..26885f9
--- /dev/null
+++ b/tools/libxl/libxl_vsnd.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2016 EPAM Systems Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+#include "libxl_internal.h"
+#include "xen/io/sndif.h"
+
+static int libxl__device_vsnd_setdefault(libxl__gc *gc, uint32_t domid,
+                                         libxl_device_vsnd *vsnd,
+                                         bool hotplug)
+{
+    return libxl__resolve_domid(gc, vsnd->backend_domname,
+                                &vsnd->backend_domid);
+}
+
+static int libxl__device_from_vsnd(libxl__gc *gc, uint32_t domid,
+                                   libxl_device_vsnd *vsnd,
+                                   libxl__device *device)
+{
+   device->backend_devid   = vsnd->devid;
+   device->backend_domid   = vsnd->backend_domid;
+   device->backend_kind    = LIBXL__DEVICE_KIND_VSND;
+   device->devid           = vsnd->devid;
+   device->domid           = domid;
+   device->kind            = LIBXL__DEVICE_KIND_VSND;
+
+   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;
+    int rc;
+
+    vsnd->devid = devid;
+    rc = libxl__xs_read_mandatory(gc, XBT_NULL,
+                                  GCSPRINTF("%s/backend", libxl_path),
+                                  &be_path);
+    if (rc) return rc;
+
+    return libxl__backendpath_parse_domid(gc, be_path, &vsnd->backend_domid);
+}
+
+static void libxl__update_config_vsnd(libxl__gc *gc,
+                                      libxl_device_vsnd *dst,
+                                      libxl_device_vsnd *src)
+{
+    dst->devid = src->devid;
+}
+
+static int libxl_device_vsnd_compare(libxl_device_vsnd *d1,
+                                     libxl_device_vsnd *d2)
+{
+    return COMPARE_DEVID(d1, d2);
+}
+
+static void libxl__device_vsnd_add(libxl__egc *egc, uint32_t domid,
+                                   libxl_device_vsnd *vsnd,
+                                   libxl__ao_device *aodev)
+{
+    libxl__device_add_async(egc, domid, &libxl__vsnd_devtype, vsnd, aodev);
+}
+
+static unsigned int libxl__rates_to_str_vsnd(char *str, uint32_t *sample_rates,
+                                             int num_sample_rates)
+{
+    unsigned int len;
+    int i;
+
+    len = 0;
+
+    if (num_sample_rates == 0) {
+        return len;
+    }
+
+    for (i = 0; i < num_sample_rates - 1; i++) {
+        if (str) {
+            len += sprintf(&str[len], "%u,", sample_rates[i]);
+        } else {
+            len += snprintf(NULL, 0, "%u,", sample_rates[i]);
+        }
+    }
+
+    if (str) {
+        len += sprintf(&str[len], "%u", sample_rates[i]);
+    } else {
+        len += snprintf(NULL, 0, "%u", sample_rates[i]);
+    }
+
+    return len;
+}
+
+static unsigned int libxl__formats_to_str_vsnd(char *str,
+                                               libxl_vsnd_pcm_format *sample_formats,
+                                               int num_sample_formats)
+{
+    unsigned int len;
+    int i;
+
+    len = 0;
+
+    if (num_sample_formats == 0) {
+        return len;
+    }
+
+    for (i = 0; i < num_sample_formats - 1; i++) {
+        if (str) {
+            len += sprintf(&str[len], "%s,",
+                           libxl_vsnd_pcm_format_to_string(sample_formats[i]));
+        } else {
+            len += snprintf(NULL, 0, "%s,",
+                            libxl_vsnd_pcm_format_to_string(sample_formats[i]));
+        }
+    }
+
+    if (str) {
+        len += sprintf(&str[len], "%s",
+                       libxl_vsnd_pcm_format_to_string(sample_formats[i]));
+    } else {
+        len += snprintf(NULL, 0, "%s",
+                        libxl_vsnd_pcm_format_to_string(sample_formats[i]));
+    }
+
+    return len;
+}
+
+static int libxl__set_params_vsnd(libxl__gc *gc, char *path,
+                                  libxl_vsnd_params *params, flexarray_t *front)
+{
+    char *buffer;
+    int len;
+    int rc;
+
+    if (params->sample_rates) {
+        // calculate required string size;
+        len = libxl__rates_to_str_vsnd(NULL, params->sample_rates,
+                                       params->num_sample_rates);
+
+        if (len) {
+            buffer = libxl__malloc(gc, len + 1);
+
+            libxl__rates_to_str_vsnd(buffer, params->sample_rates,
+                                     params->num_sample_rates);
+            rc = flexarray_append_pair(front,
+                                       GCSPRINTF("%s"XENSND_FIELD_SAMPLE_RATES,
+                                                 path), buffer);
+            if (rc) return rc;
+        }
+    }
+
+    if (params->sample_formats) {
+        // calculate required string size;
+        len = libxl__formats_to_str_vsnd(NULL, params->sample_formats,
+                                         params->num_sample_formats);
+
+        if (len) {
+            buffer = libxl__malloc(gc, len + 1);
+
+            libxl__formats_to_str_vsnd(buffer, params->sample_formats,
+                                     params->num_sample_formats);
+            rc = flexarray_append_pair(front,
+                                       GCSPRINTF("%s"XENSND_FIELD_SAMPLE_FORMATS,
+                                                 path), buffer);
+            if (rc) return rc;
+        }
+    }
+
+    if (params->channels_min) {
+        rc = flexarray_append_pair(front,
+                                   GCSPRINTF("%s"XENSND_FIELD_CHANNELS_MIN, path),
+                                   GCSPRINTF("%u", params->channels_min));
+        if (rc) return rc;
+    }
+
+    if (params->channels_max) {
+        rc = flexarray_append_pair(front,
+                                   GCSPRINTF("%s"XENSND_FIELD_CHANNELS_MAX, path),
+                                   GCSPRINTF("%u", params->channels_max));
+        if (rc) return rc;
+    }
+
+    if (params->buffer_size) {
+        rc = flexarray_append_pair(front,
+                                   GCSPRINTF("%s"XENSND_FIELD_BUFFER_SIZE, path),
+                                   GCSPRINTF("%u", params->buffer_size));
+        if (rc) return rc;
+    }
+
+    return 0;
+}
+
+static int libxl__set_streams_vsnd(libxl__gc *gc, char *path,
+                                   libxl_vsnd_stream *streams,
+                                   int num_streams, flexarray_t *front)
+{
+    int i;
+    int rc;
+
+    for (i = 0; i < num_streams; i++) {
+        rc = flexarray_append_pair(front,
+                 GCSPRINTF("%s%d/"XENSND_FIELD_STREAM_UNIQUE_ID, path, i),
+                 GCSPRINTF("%u", streams[i].id));
+        if (rc) return rc;
+
+        const char *type = libxl_vsnd_stream_type_to_string(streams[i].type);
+
+        if (type) {
+            rc = flexarray_append_pair(front,
+                     GCSPRINTF("%s%d/"XENSND_FIELD_TYPE, path, i),
+                     (char *)type);
+            if (rc) return rc;
+        }
+
+        rc = libxl__set_params_vsnd(gc, GCSPRINTF("%s%d/", path, i),
+                                    &streams[i].params, front);
+        if (rc) return rc;
+    }
+
+    return 0;
+}
+
+static int libxl__set_pcms_vsnd(libxl__gc *gc, libxl_vsnd_pcm *pcms,
+                                int num_pcms, flexarray_t *front)
+{
+    int i;
+    int rc;
+
+    for (i = 0; i < num_pcms; i++) {
+        if (pcms[i].name) {
+            rc = flexarray_append_pair(front,
+                                       GCSPRINTF("%d/"XENSND_FIELD_DEVICE_NAME, i),
+                                       pcms[i].name);
+            if (rc) return rc;
+        }
+
+        char *path = GCSPRINTF("%d/", i);
+
+        rc = libxl__set_params_vsnd(gc, path, &pcms[i].params, front);
+        if (rc) return rc;
+
+        rc = libxl__set_streams_vsnd(gc, path, pcms[i].streams,
+                                     pcms[i].num_vsnd_streams, front);
+        if (rc) return rc;
+    }
+
+    return 0;
+}
+
+static int libxl__set_xenstore_vsnd(libxl__gc *gc, uint32_t domid,
+                                    libxl_device_vsnd *vsnd,
+                                    flexarray_t *back, flexarray_t *front,
+                                    flexarray_t *ro_front)
+{
+    int rc;
+
+    if (vsnd->long_name) {
+        rc = flexarray_append_pair(front, XENSND_FIELD_VCARD_LONG_NAME,
+                                   vsnd->long_name);
+        if (rc) return rc;
+    }
+
+    if (vsnd->short_name) {
+        rc = flexarray_append_pair(front, XENSND_FIELD_VCARD_SHORT_NAME,
+                                   vsnd->short_name);
+        if (rc) return rc;
+    }
+
+    rc = libxl__set_params_vsnd(gc, "", &vsnd->params, front);
+    if (rc) return rc;
+
+    rc = libxl__set_pcms_vsnd(gc, vsnd->pcms, vsnd->num_vsnd_pcms, front);
+    if (rc) return rc;
+
+    return 0;
+}
+
+LIBXL_DEFINE_DEVICE_ADD(vsnd)
+static LIBXL_DEFINE_DEVICES_ADD(vsnd)
+LIBXL_DEFINE_DEVICE_REMOVE(vsnd)
+static LIBXL_DEFINE_UPDATE_DEVID(vsnd, "vsnd")
+
+DEFINE_DEVICE_TYPE_STRUCT(vsnd,
+    .update_config = (device_update_config_fn_t) libxl__update_config_vsnd,
+    .from_xenstore = (device_from_xenstore_fn_t) libxl__vsnd_from_xenstore,
+    .set_xenstore_config = (device_set_xenstore_config_fn_t)
+                           libxl__set_xenstore_vsnd
+);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
