diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index ffdd799..71831a3 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -906,33 +906,47 @@ static int hda_audio_init_duplex(HDACodecDevice *hda)
     return hda_audio_init(hda, &duplex);
 }
 
-static HDACodecDeviceInfo hda_audio_info_output = {
-    .qdev.name    = "hda-output",
-    .qdev.desc    = "HDA Audio Codec, output-only",
-    .qdev.size    = sizeof(HDAAudioState),
-    .qdev.vmsd    = &vmstate_hda_audio,
-    .qdev.props   = hda_audio_properties,
-    .init         = hda_audio_init_output,
-    .exit         = hda_audio_exit,
-    .command      = hda_audio_command,
-    .stream       = hda_audio_stream,
+static void hda_audio_output_class_init(ObjectClass *klass, void *data)
+{
+    HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
+
+    k->init = hda_audio_init_output;
+    k->exit = hda_audio_exit;
+    k->command = hda_audio_command;
+    k->stream = hda_audio_stream;
+}
+
+static DeviceInfo hda_audio_output_info = {
+    .name = "hda-output",
+    .desc = "HDA Audio Codec, output-only",
+    .size = sizeof(HDAAudioState),
+    .vmsd = &vmstate_hda_audio,
+    .props = hda_audio_properties,
+    .class_init = hda_audio_output_class_init,
 };
 
-static HDACodecDeviceInfo hda_audio_info_duplex = {
-    .qdev.name    = "hda-duplex",
-    .qdev.desc    = "HDA Audio Codec, duplex",
-    .qdev.size    = sizeof(HDAAudioState),
-    .qdev.vmsd    = &vmstate_hda_audio,
-    .qdev.props   = hda_audio_properties,
-    .init         = hda_audio_init_duplex,
-    .exit         = hda_audio_exit,
-    .command      = hda_audio_command,
-    .stream       = hda_audio_stream,
+static void hda_audio_duplex_class_init(ObjectClass *klass, void *data)
+{
+    HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
+
+    k->init = hda_audio_init_duplex;
+    k->exit = hda_audio_exit;
+    k->command = hda_audio_command;
+    k->stream = hda_audio_stream;
+}
+
+static DeviceInfo hda_audio_duplex_info = {
+    .name = "hda-duplex",
+    .desc = "HDA Audio Codec, duplex",
+    .size = sizeof(HDAAudioState),
+    .vmsd = &vmstate_hda_audio,
+    .props = hda_audio_properties,
+    .class_init = hda_audio_duplex_class_init,
 };
 
 static void hda_audio_register(void)
 {
-    hda_codec_register(&hda_audio_info_output);
-    hda_codec_register(&hda_audio_info_duplex);
+    hda_codec_register(&hda_audio_output_info);
+    hda_codec_register(&hda_audio_duplex_info);
 }
 device_init(hda_audio_register);
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 09459b8..97a6216 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -50,10 +50,9 @@ void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
 static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
 {
     HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus);
-    HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
-    HDACodecDeviceInfo *info = DO_UPCAST(HDACodecDeviceInfo, qdev, base);
+    HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev);
+    HDACodecDeviceClass *hcc = HDA_CODEC_DEVICE_GET_CLASS(dev);
 
-    dev->info = info;
     if (dev->cad == -1) {
         dev->cad = bus->next_cad;
     }
@@ -61,25 +60,26 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
         return -1;
     }
     bus->next_cad = dev->cad + 1;
-    return info->init(dev);
+    return hcc->init(dev);
 }
 
 static int hda_codec_dev_exit(DeviceState *qdev)
 {
-    HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+    HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev);
+    HDACodecDeviceClass *hcc = HDA_CODEC_DEVICE_GET_CLASS(dev);
 
-    if (dev->info->exit) {
-        dev->info->exit(dev);
+    if (hcc->exit) {
+        hcc->exit(dev);
     }
     return 0;
 }
 
-void hda_codec_register(HDACodecDeviceInfo *info)
+void hda_codec_register(DeviceInfo *info)
 {
-    info->qdev.init = hda_codec_dev_init;
-    info->qdev.exit = hda_codec_dev_exit;
-    info->qdev.bus_info = &hda_codec_bus_info;
-    qdev_register(&info->qdev);
+    info->init = hda_codec_dev_init;
+    info->exit = hda_codec_dev_exit;
+    info->bus_info = &hda_codec_bus_info;
+    qdev_register_subclass(info, TYPE_HDA_CODEC_DEVICE);
 }
 
 HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
@@ -283,6 +283,7 @@ static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
 {
     uint32_t cad, nid, data;
     HDACodecDevice *codec;
+    HDACodecDeviceClass *hcc;
 
     cad = (verb >> 28) & 0x0f;
     if (verb & (1 << 27)) {
@@ -298,7 +299,8 @@ static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
         dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__);
         return -1;
     }
-    codec->info->command(codec, nid, data);
+    hcc = HDA_CODEC_DEVICE_GET_CLASS(codec);
+    hcc->command(codec, nid, data);
     return 0;
 }
 
@@ -491,9 +493,11 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn
     HDACodecDevice *cdev;
 
     QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+        HDACodecDeviceClass *hcc;
         cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
-        if (cdev->info->stream) {
-            cdev->info->stream(cdev, stream, running, output);
+        hcc = HDA_CODEC_DEVICE_GET_CLASS(cdev);
+        if (hcc->stream) {
+            hcc->stream(cdev, stream, running, output);
         }
     }
 }
@@ -1262,9 +1266,18 @@ static PCIDeviceInfo intel_hda_info = {
     }
 };
 
+static TypeInfo hda_codec_device_type_info = {
+    .name = TYPE_HDA_CODEC_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(HDACodecDevice),
+    .abstract = true,
+    .class_size = sizeof(HDACodecDeviceClass),
+};
+
 static void intel_hda_register(void)
 {
     pci_qdev_register(&intel_hda_info);
+    type_register_static(&hda_codec_device_type_info);
 }
 device_init(intel_hda_register);
 
diff --git a/hw/intel-hda.h b/hw/intel-hda.h
index 65fd2a8..f523587 100644
--- a/hw/intel-hda.h
+++ b/hw/intel-hda.h
@@ -6,9 +6,16 @@
 /* --------------------------------------------------------------------- */
 /* hda bus                                                               */
 
+#define TYPE_HDA_CODEC_DEVICE "hda-codec"
+#define HDA_CODEC_DEVICE(obj) \
+     OBJECT_CHECK(HDACodecDevice, (obj), TYPE_HDA_CODEC_DEVICE)
+#define HDA_CODEC_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(HDACodecDeviceClass, (klass), TYPE_HDA_CODEC_DEVICE)
+#define HDA_CODEC_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(HDACodecDeviceClass, (obj), TYPE_HDA_CODEC_DEVICE)
+
 typedef struct HDACodecBus HDACodecBus;
 typedef struct HDACodecDevice HDACodecDevice;
-typedef struct HDACodecDeviceInfo HDACodecDeviceInfo;
 
 typedef void (*hda_codec_response_func)(HDACodecDevice *dev,
                                         bool solicited, uint32_t response);
@@ -23,24 +30,25 @@ struct HDACodecBus {
     hda_codec_xfer_func xfer;
 };
 
-struct HDACodecDevice {
-    DeviceState         qdev;
-    HDACodecDeviceInfo  *info;
-    uint32_t            cad;    /* codec address */
-};
+typedef struct HDACodecDeviceClass
+{
+    DeviceClass parent_class;
 
-struct HDACodecDeviceInfo {
-    DeviceInfo qdev;
     int (*init)(HDACodecDevice *dev);
     int (*exit)(HDACodecDevice *dev);
     void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
     void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output);
+} HDACodecDeviceClass;
+
+struct HDACodecDevice {
+    DeviceState         qdev;
+    uint32_t            cad;    /* codec address */
 };
 
 void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
                         hda_codec_response_func response,
                         hda_codec_xfer_func xfer);
-void hda_codec_register(HDACodecDeviceInfo *info);
+void hda_codec_register(DeviceInfo *info);
 HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad);
 
 void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response);
