diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
index 537face..a363993 100644
--- a/hw/audio/intel-hda.c
+++ b/hw/audio/intel-hda.c
@@ -36,9 +36,16 @@ static Property hda_props[] = {
     DEFINE_PROP_END_OF_LIST()
 };
 
+static void hda_codec_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_HDA_CODEC_DEVICE;
+}
+
 static const TypeInfo hda_codec_bus_info = {
     .name = TYPE_HDA_BUS,
     .parent = TYPE_BUS,
+    .class_init = hda_codec_bus_class_init,
     .instance_size = sizeof(HDACodecBus),
 };
 
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index 17d29e7..09bfdda 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -60,6 +60,10 @@
 #define TYPE_FLOPPY_BUS "floppy-bus"
 #define FLOPPY_BUS(obj) OBJECT_CHECK(FloppyBus, (obj), TYPE_FLOPPY_BUS)
 
+#define TYPE_FLOPPY_DRIVE "floppy"
+#define FLOPPY_DRIVE(obj) \
+     OBJECT_CHECK(FloppyDrive, (obj), TYPE_FLOPPY_DRIVE)
+
 typedef struct FDCtrl FDCtrl;
 typedef struct FDrive FDrive;
 static FDrive *get_drv(FDCtrl *fdctrl, int unit);
@@ -69,9 +73,16 @@ typedef struct FloppyBus {
     FDCtrl *fdc;
 } FloppyBus;
 
+static void floppy_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_FLOPPY_DRIVE;
+}
+
 static const TypeInfo floppy_bus_info = {
     .name = TYPE_FLOPPY_BUS,
     .parent = TYPE_BUS,
+    .class_init = floppy_bus_class_init,
     .instance_size = sizeof(FloppyBus),
 };
 
@@ -483,10 +494,6 @@ static const BlockDevOps fd_block_ops = {
 };
 
 
-#define TYPE_FLOPPY_DRIVE "floppy"
-#define FLOPPY_DRIVE(obj) \
-     OBJECT_CHECK(FloppyDrive, (obj), TYPE_FLOPPY_DRIVE)
-
 typedef struct FloppyDrive {
     DeviceState     qdev;
     uint32_t        unit;
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 7975c2c..215e180 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -832,6 +832,7 @@ static void virtser_bus_class_init(ObjectClass *klass, void *data)
 {
     BusClass *k = BUS_CLASS(klass);
     k->print_dev = virtser_bus_dev_print;
+    k->device_type = TYPE_VIRTIO_SERIAL_PORT;
 }
 
 static const TypeInfo virtser_bus_info = {
diff --git a/hw/core/bus.c b/hw/core/bus.c
index cf383fc..d2bf717 100644
--- a/hw/core/bus.c
+++ b/hw/core/bus.c
@@ -21,6 +21,7 @@
 #include "qemu-common.h"
 #include "hw/qdev.h"
 #include "qapi/error.h"
+#include "qapi-visit.h"
 
 static void qbus_set_hotplug_handler_internal(BusState *bus, Object *handler,
                                               Error **errp)
@@ -191,8 +192,15 @@ static void bus_set_realized(Object *obj, bool value, Error **errp)
 static void qbus_initfn(Object *obj)
 {
     BusState *bus = BUS(obj);
+    BusClass *bc = BUS_GET_CLASS(bus);
 
     QTAILQ_INIT(&bus->children);
+
+    if (bc->device_type) {
+        bus->accepted_device_types = g_new0(strList, 1);
+        bus->accepted_device_types->value = g_strdup(bc->device_type);
+    }
+
     object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY,
                              TYPE_HOTPLUG_HANDLER,
                              (Object **)&bus->hotplug_handler,
@@ -208,12 +216,25 @@ static char *default_bus_get_fw_dev_path(DeviceState *dev)
     return g_strdup(object_get_typename(OBJECT(dev)));
 }
 
+static void bus_get_device_type(Object *obj, Visitor *v,
+                                 const char *name, void *opaque,
+                                 Error **errp)
+{
+    BusState *bus = BUS(obj);
+
+    visit_type_strList(v, NULL, &bus->accepted_device_types, errp);
+}
+
 static void bus_class_init(ObjectClass *class, void *data)
 {
     BusClass *bc = BUS_CLASS(class);
 
     class->unparent = bus_unparent;
     bc->get_fw_dev_path = default_bus_get_fw_dev_path;
+
+    object_class_property_add(class, "accepted-device-types", "strList",
+                              bus_get_device_type, NULL, NULL, NULL,
+                              &error_abort);
 }
 
 static void qbus_finalize(Object *obj)
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index c0f560b..c065eb8 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -76,6 +76,7 @@ static void system_bus_class_init(ObjectClass *klass, void *data)
 
     k->print_dev = sysbus_dev_print;
     k->get_fw_dev_path = sysbus_get_fw_dev_path;
+    k->device_type = TYPE_SYS_BUS_DEVICE;
 }
 
 static const TypeInfo system_bus_info = {
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index abd4c4c..81b6ae4 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -35,9 +35,16 @@ static Property i2c_props[] = {
 #define TYPE_I2C_BUS "i2c-bus"
 #define I2C_BUS(obj) OBJECT_CHECK(I2CBus, (obj), TYPE_I2C_BUS)
 
+static void i2c_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_I2C_SLAVE;
+}
+
 static const TypeInfo i2c_bus_info = {
     .name = TYPE_I2C_BUS,
     .parent = TYPE_BUS,
+    .class_init = i2c_bus_class_init,
     .instance_size = sizeof(I2CBus),
 };
 
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index dbaa75c..b526f85 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -43,6 +43,7 @@ static void ide_bus_class_init(ObjectClass *klass, void *data)
     BusClass *k = BUS_CLASS(klass);
 
     k->get_fw_dev_path = idebus_get_fw_dev_path;
+    k->device_type = TYPE_IDE_DEVICE;
 }
 
 static void idebus_unrealize(DeviceState *qdev, Error **errp)
diff --git a/hw/input/adb.c b/hw/input/adb.c
index 43d3205..c6a2b31 100644
--- a/hw/input/adb.c
+++ b/hw/input/adb.c
@@ -121,9 +121,16 @@ int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask)
     return olen;
 }
 
+static void adb_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_ADB_DEVICE;
+}
+
 static const TypeInfo adb_bus_type_info = {
     .name = TYPE_ADB_BUS,
     .parent = TYPE_BUS,
+    .class_init = adb_bus_class_init,
     .instance_size = sizeof(ADBBusState),
 };
 
diff --git a/hw/ipack/ipack.c b/hw/ipack/ipack.c
index 6021e6d..f22c504 100644
--- a/hw/ipack/ipack.c
+++ b/hw/ipack/ipack.c
@@ -106,9 +106,16 @@ static const TypeInfo ipack_device_info = {
     .abstract      = true,
 };
 
+static void ipack_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_IPACK_DEVICE;
+}
+
 static const TypeInfo ipack_bus_info = {
     .name = TYPE_IPACK_BUS,
     .parent = TYPE_BUS,
+    .class_init = ipack_bus_class_init,
     .instance_size = sizeof(IPackBus),
 };
 
diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c
index 9d07b11..aad7669 100644
--- a/hw/isa/isa-bus.c
+++ b/hw/isa/isa-bus.c
@@ -36,6 +36,7 @@ static void isa_bus_class_init(ObjectClass *klass, void *data)
 
     k->print_dev = isabus_dev_print;
     k->get_fw_dev_path = isabus_get_fw_dev_path;
+    k->device_type = TYPE_ISA_DEVICE;
 }
 
 static const TypeInfo isa_dma_info = {
diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c
index e4a7ba4..4b0d565 100644
--- a/hw/misc/auxbus.c
+++ b/hw/misc/auxbus.c
@@ -57,6 +57,7 @@ static void aux_bus_class_init(ObjectClass *klass, void *data)
      * in monitor.
      */
     k->print_dev = aux_slave_dev_print;
+    k->device_type = TYPE_AUX_SLAVE;
 }
 
 AUXBus *aux_init_bus(DeviceState *parent, const char *name)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 24fae16..74b8fef 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -152,6 +152,7 @@ static void pci_bus_class_init(ObjectClass *klass, void *data)
     k->realize = pci_bus_realize;
     k->unrealize = pci_bus_unrealize;
     k->reset = pcibus_reset;
+    k->device_type = TYPE_PCI_DEVICE;
 
     pbc->is_root = pcibus_is_root;
     pbc->bus_num = pcibus_num;
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index cc1e09c..c70b9b9 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -61,6 +61,7 @@ static void spapr_vio_bus_class_init(ObjectClass *klass, void *data)
 
     k->get_dev_path = spapr_vio_get_dev_name;
     k->get_fw_dev_path = spapr_vio_get_dev_name;
+    k->device_type = TYPE_VIO_SPAPR_DEVICE;
 }
 
 static const TypeInfo spapr_vio_bus_info = {
diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c
index 9a7f7ee..8a6c1ae 100644
--- a/hw/s390x/css-bridge.c
+++ b/hw/s390x/css-bridge.c
@@ -17,6 +17,7 @@
 #include "hw/s390x/css.h"
 #include "ccw-device.h"
 #include "hw/s390x/css-bridge.h"
+#include "hw/s390x/virtio-ccw.h"
 
 /*
  * Invoke device-specific unplug handler, disable the subchannel
@@ -81,6 +82,7 @@ static void virtual_css_bus_class_init(ObjectClass *klass, void *data)
 
     k->reset = virtual_css_bus_reset;
     k->get_dev_path = virtual_css_bus_get_dev_path;
+    k->device_type = TYPE_VIRTIO_CCW_DEVICE;
 }
 
 static const TypeInfo virtual_css_bus_info = {
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index 34b2faf..f2562ce 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -307,6 +307,7 @@ static void sclp_events_bus_class_init(ObjectClass *klass, void *data)
     BusClass *bc = BUS_CLASS(klass);
 
     bc->realize = sclp_events_bus_realize;
+    bc->device_type = TYPE_SCLP_EVENT;
 }
 
 static const TypeInfo sclp_events_bus_info = {
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 63f6248..7470fdd 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -783,10 +783,17 @@ static const TypeInfo s390_pcihost_info = {
     }
 };
 
+static void s390_pcibus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_S390_PCI_DEVICE;
+}
+
 static const TypeInfo s390_pcibus_info = {
     .name = TYPE_S390_PCI_BUS,
     .parent = TYPE_BUS,
     .instance_size = sizeof(S390PCIBus),
+    .class_init = s390_pcibus_class_init,
 };
 
 static uint16_t s390_pci_generate_uid(void)
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 297216d..9faf45f 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -31,6 +31,7 @@ static void scsi_bus_class_init(ObjectClass *klass, void *data)
 
     k->get_dev_path = scsibus_get_dev_path;
     k->get_fw_dev_path = scsibus_get_fw_dev_path;
+    k->device_type = TYPE_SCSI_DEVICE;
     hc->unplug = qdev_simple_device_unplug_cb;
 }
 
diff --git a/hw/sd/core.c b/hw/sd/core.c
index 14c2bdf..49b9f59 100644
--- a/hw/sd/core.c
+++ b/hw/sd/core.c
@@ -131,11 +131,18 @@ void sdbus_set_readonly(SDBus *sdbus, bool readonly)
     }
 }
 
+static void sd_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_SD_CARD;
+}
+
 static const TypeInfo sd_bus_info = {
     .name = TYPE_SD_BUS,
     .parent = TYPE_BUS,
     .instance_size = sizeof(SDBus),
     .class_size = sizeof(SDBusClass),
+    .class_init = sd_bus_class_init,
 };
 
 static void sd_bus_register_types(void)
diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c
index 7eaaf56..c48920d 100644
--- a/hw/ssi/ssi.c
+++ b/hw/ssi/ssi.c
@@ -22,10 +22,17 @@ struct SSIBus {
 #define TYPE_SSI_BUS "SSI"
 #define SSI_BUS(obj) OBJECT_CHECK(SSIBus, (obj), TYPE_SSI_BUS)
 
+static void ssi_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_SSI_SLAVE;
+}
+
 static const TypeInfo ssi_bus_info = {
     .name = TYPE_SSI_BUS,
     .parent = TYPE_BUS,
     .instance_size = sizeof(SSIBus),
+    .class_init = ssi_bus_class_init,
 };
 
 static void ssi_cs_default(void *opaque, int n, int level)
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index 25913ad..2cb7fa4 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -33,6 +33,7 @@ static void usb_bus_class_init(ObjectClass *klass, void *data)
     k->print_dev = usb_bus_dev_print;
     k->get_dev_path = usb_get_dev_path;
     k->get_fw_dev_path = usb_get_fw_dev_path;
+    k->device_type = TYPE_USB_DEVICE;
     hc->unplug = qdev_simple_device_unplug_cb;
 }
 
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 89e11b6..2721f0c 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -1180,10 +1180,17 @@ static Property ccid_props[] = {
 #define TYPE_CCID_BUS "ccid-bus"
 #define CCID_BUS(obj) OBJECT_CHECK(CCIDBus, (obj), TYPE_CCID_BUS)
 
+static void ccid_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_CCID_CARD;
+}
+
 static const TypeInfo ccid_bus_info = {
     .name = TYPE_CCID_BUS,
     .parent = TYPE_BUS,
     .instance_size = sizeof(CCIDBus),
+    .class_init = ccid_bus_class_init,
 };
 
 void ccid_card_send_apdu_to_guest(CCIDCardState *card,
diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c
index d6c0c72..815f3dd 100644
--- a/hw/virtio/virtio-bus.c
+++ b/hw/virtio/virtio-bus.c
@@ -293,6 +293,7 @@ static void virtio_bus_class_init(ObjectClass *klass, void *data)
     BusClass *bus_class = BUS_CLASS(klass);
     bus_class->get_dev_path = virtio_bus_get_dev_path;
     bus_class->get_fw_dev_path = virtio_bus_get_fw_dev_path;
+    bus_class->device_type = TYPE_VIRTIO_DEVICE;
 }
 
 static const TypeInfo virtio_bus_info = {
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 2c97347..a7f9ac4 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -207,6 +207,13 @@ struct BusClass {
     int max_dev;
     /* number of automatically allocated bus ids (e.g. ide.0) */
     int automatic_ids;
+
+    /* default device type for 'accepted-device-type' property
+     *
+     * Most buses return only BusClass::device_type on accepted-device-types,
+     * but on some cases bus instances may override it.
+     */
+    const char *device_type;
 };
 
 typedef struct BusChild {
@@ -228,6 +235,7 @@ struct BusState {
     HotplugHandler *hotplug_handler;
     int max_index;
     bool realized;
+    strList *accepted_device_types;
     QTAILQ_HEAD(ChildrenHead, BusChild) children;
     QLIST_ENTRY(BusState) sibling;
 };
