diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 56c358a0ec24cf5d2b8ec8204433cb8f2c6f28a4..3a5f48df7a27511a5bf9231e547360f11facdd7b 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -126,6 +126,10 @@ void device_free(struct udevice *dev)
 	}
 	if (dev->parent) {
 		size = dev->parent->driver->per_child_auto_alloc_size;
+		if (!size) {
+			size = dev->parent->uclass->uc_drv->
+					per_child_auto_alloc_size;
+		}
 		if (size) {
 			free(dev->parent_priv);
 			dev->parent_priv = NULL;
diff --git a/drivers/core/device.c b/drivers/core/device.c
index f78b78a299edfdcefb1fe0e2a6f71b2fc9363a60..78bc460d35fb014158f9b2ba88abfdfac3bef5d7 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -201,6 +201,10 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
 	/* Ensure all parents are probed */
 	if (dev->parent) {
 		size = dev->parent->driver->per_child_auto_alloc_size;
+		if (!size) {
+			size = dev->parent->uclass->uc_drv->
+					per_child_auto_alloc_size;
+		}
 		if (size) {
 			dev->parent_priv = calloc(1, size);
 			if (!dev->parent_priv) {
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 9000b22c38de9a263646a992932adb61b16e1496..ac6c85072c9517d640ec6c8ceb2e50bac826f243 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -63,6 +63,9 @@ struct udevice;
  * @per_device_auto_alloc_size: Each device can hold private data owned
  * by the uclass. If required this will be automatically allocated if this
  * value is non-zero.
+ * @per_child_auto_alloc_size: Each child device (of a parent in this
+ * uclass) can hold parent data for the device/uclass. This value is only
+ * used as a falback if this member is 0 in the driver.
  * @per_child_platdata_auto_alloc_size: A bus likes to store information about
  * its children. If non-zero this is the size of this data, to be allocated
  * in the child device's parent_platdata pointer. This value is only used as
@@ -82,6 +85,7 @@ struct uclass_driver {
 	int (*destroy)(struct uclass *class);
 	int priv_auto_alloc_size;
 	int per_device_auto_alloc_size;
+	int per_child_auto_alloc_size;
 	int per_child_platdata_auto_alloc_size;
 	const void *ops;
 	uint32_t flags;
diff --git a/test/dm/bus.c b/test/dm/bus.c
index 972c44979084f5e765cc227f1d400f5f8ea2986b..e9096970628e70ec0f0e6ce9f99c4eebef25b902 100644
--- a/test/dm/bus.c
+++ b/test/dm/bus.c
@@ -192,7 +192,7 @@ DM_TEST(dm_test_bus_children_iterators,
 	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 
 /* Test that the bus can store data about each child */
-static int dm_test_bus_parent_data(struct dm_test_state *dms)
+static int test_bus_parent_data(struct dm_test_state *dms)
 {
 	struct dm_test_parent_data *parent_data;
 	struct udevice *bus, *dev;
@@ -251,9 +251,36 @@ static int dm_test_bus_parent_data(struct dm_test_state *dms)
 
 	return 0;
 }
-
+/* Test that the bus can store data about each child */
+static int dm_test_bus_parent_data(struct dm_test_state *dms)
+{
+	return test_bus_parent_data(dms);
+}
 DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 
+/* As above but the size is controlled by the uclass */
+static int dm_test_bus_parent_data_uclass(struct dm_test_state *dms)
+{
+	struct udevice *bus;
+	int size;
+	int ret;
+
+	/* Set the driver size to 0 so that the uclass size is used */
+	ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
+	size = bus->driver->per_child_auto_alloc_size;
+	bus->uclass->uc_drv->per_child_auto_alloc_size = size;
+	bus->driver->per_child_auto_alloc_size = 0;
+	ret = test_bus_parent_data(dms);
+	if (ret)
+		return ret;
+	bus->uclass->uc_drv->per_child_auto_alloc_size = 0;
+	bus->driver->per_child_auto_alloc_size = size;
+
+	return 0;
+}
+DM_TEST(dm_test_bus_parent_data_uclass,
+	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
 /* Test that the bus ops are called when a child is probed/removed */
 static int dm_test_bus_parent_ops(struct dm_test_state *dms)
 {