diff --git a/drivers/net/failsafe/failsafe_eal.c b/drivers/net/failsafe/failsafe_eal.c
index ce1633f13..8a888b1ff 100644
--- a/drivers/net/failsafe/failsafe_eal.c
+++ b/drivers/net/failsafe/failsafe_eal.c
@@ -144,8 +144,7 @@ fs_bus_uninit(struct rte_eth_dev *dev)
 	int ret = 0;
 
 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) {
-		sdev_ret = rte_eal_hotplug_remove(sdev->bus->name,
-							sdev->dev->name);
+		sdev_ret = rte_dev_remove(sdev->dev);
 		if (sdev_ret) {
 			ERROR("Failed to remove requested device %s (err: %d)",
 			      sdev->dev->name, sdev_ret);
diff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c
index 51c96f78b..f2512c430 100644
--- a/drivers/net/failsafe/failsafe_ether.c
+++ b/drivers/net/failsafe/failsafe_ether.c
@@ -282,8 +282,7 @@ fs_dev_remove(struct sub_device *sdev)
 		sdev->state = DEV_PROBED;
 		/* fallthrough */
 	case DEV_PROBED:
-		ret = rte_eal_hotplug_remove(sdev->bus->name,
-					     sdev->dev->name);
+		ret = rte_dev_remove(sdev->dev);
 		if (ret) {
 			ERROR("Bus detach failed for sub_device %u",
 			      SUB_ID(sdev));
diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index ce6d145fb..5dcc1403f 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -129,46 +129,61 @@ int rte_eal_dev_detach(struct rte_device *dev)
 
 int
 rte_eal_hotplug_add(const char *busname, const char *devname,
-		    const char *devargs)
+		    const char *drvargs)
 {
-	struct rte_bus *bus;
-	struct rte_device *dev;
-	struct rte_devargs *da;
 	int ret;
+	char *devargs = NULL;
+	int size, length = -1;
 
-	bus = rte_bus_find_by_name(busname);
-	if (bus == NULL) {
-		RTE_LOG(ERR, EAL, "Cannot find bus (%s)\n", busname);
-		return -ENOENT;
-	}
+	do { /* 2 iterations: first is to know string length */
+		size = length + 1;
+		length = snprintf(devargs, size, "%s:%s,%s", busname, devname, drvargs);
+		if (length >= size)
+			devargs = malloc(length + 1);
+		if (devargs == NULL)
+			return -ENOMEM;
+	} while (size == 0);
 
-	if (bus->plug == NULL) {
-		RTE_LOG(ERR, EAL, "Function plug not supported by bus (%s)\n",
-			bus->name);
-		return -ENOTSUP;
-	}
+	ret = rte_dev_probe(devargs);
+
+	free(devargs);
+	return ret;
+}
+
+int __rte_experimental
+rte_dev_probe(const char *devargs)
+{
+	struct rte_device *dev;
+	struct rte_devargs *da;
+	int ret;
 
 	da = calloc(1, sizeof(*da));
 	if (da == NULL)
 		return -ENOMEM;
 
-	ret = rte_devargs_parsef(da, "%s:%s,%s",
-				 busname, devname, devargs);
+	ret = rte_devargs_parse(da, devargs);
 	if (ret)
 		goto err_devarg;
 
+	if (da->bus->plug == NULL) {
+		RTE_LOG(ERR, EAL, "Function plug not supported by bus (%s)\n",
+			da->bus->name);
+		ret = -ENOTSUP;
+		goto err_devarg;
+	}
+
 	ret = rte_devargs_insert(da);
 	if (ret)
 		goto err_devarg;
 
-	ret = bus->scan();
+	ret = da->bus->scan();
 	if (ret)
 		goto err_devarg;
 
-	dev = bus->find_device(NULL, cmp_dev_name, devname);
+	dev = da->bus->find_device(NULL, cmp_dev_name, da->name);
 	if (dev == NULL) {
 		RTE_LOG(ERR, EAL, "Cannot find device (%s)\n",
-			devname);
+			da->name);
 		ret = -ENODEV;
 		goto err_devarg;
 	}
@@ -178,7 +193,7 @@ rte_eal_hotplug_add(const char *busname, const char *devname,
 		return -EEXIST;
 	}
 
-	ret = bus->plug(dev);
+	ret = dev->bus->plug(dev);
 	if (ret) {
 		RTE_LOG(ERR, EAL, "Driver cannot attach the device (%s)\n",
 			dev->name);
@@ -197,9 +212,8 @@ rte_eal_hotplug_add(const char *busname, const char *devname,
 int
 rte_eal_hotplug_remove(const char *busname, const char *devname)
 {
-	struct rte_bus *bus;
 	struct rte_device *dev;
-	int ret;
+	struct rte_bus *bus;
 
 	bus = rte_bus_find_by_name(busname);
 	if (bus == NULL) {
@@ -207,24 +221,32 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)
 		return -ENOENT;
 	}
 
-	if (bus->unplug == NULL) {
-		RTE_LOG(ERR, EAL, "Function unplug not supported by bus (%s)\n",
-			bus->name);
-		return -ENOTSUP;
-	}
-
 	dev = bus->find_device(NULL, cmp_dev_name, devname);
 	if (dev == NULL) {
 		RTE_LOG(ERR, EAL, "Cannot find plugged device (%s)\n", devname);
 		return -EINVAL;
 	}
 
+	return rte_dev_remove(dev);
+}
+
+int __rte_experimental
+rte_dev_remove(struct rte_device *dev)
+{
+	int ret;
+
 	if (dev->driver == NULL) {
 		RTE_LOG(ERR, EAL, "Device is already unplugged\n");
 		return -ENOENT;
 	}
 
-	ret = bus->unplug(dev);
+	if (dev->bus->unplug == NULL) {
+		RTE_LOG(ERR, EAL, "Function unplug not supported by bus (%s)\n",
+			dev->bus->name);
+		return -ENOTSUP;
+	}
+
+	ret = dev->bus->unplug(dev);
 	if (ret)
 		RTE_LOG(ERR, EAL, "Driver cannot detach the device (%s)\n",
 			dev->name);
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index d6c5d48a9..036180ff3 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -197,13 +197,26 @@ int rte_eal_dev_detach(struct rte_device *dev);
  * @param devname
  *   The device name. Based on this device name, eal will identify a driver
  *   capable of handling it and pass it to the driver probing function.
- * @param devargs
+ * @param drvargs
  *   Device arguments to be passed to the driver.
  * @return
  *   0 on success, negative on error.
  */
 int rte_eal_hotplug_add(const char *busname, const char *devname,
-			const char *devargs);
+			const char *drvargs);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Add matching devices.
+ *
+ * @param devargs
+ *   Device arguments including bus, class and driver properties.
+ * @return
+ *   0 on success, negative on error.
+ */
+int __rte_experimental rte_dev_probe(const char *devargs);
 
 /**
  * Hotplug remove a given device from a specific bus.
@@ -217,6 +230,19 @@ int rte_eal_hotplug_add(const char *busname, const char *devname,
  */
 int rte_eal_hotplug_remove(const char *busname, const char *devname);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Remove one device.
+ *
+ * @param dev
+ *   Data structure of the device to remove.
+ * @return
+ *   0 on success, negative on error.
+ */
+int __rte_experimental rte_dev_remove(struct rte_device *dev);
+
 /**
  * Device comparison function.
  *
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 6bff37f4b..2ea7a870a 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -281,6 +281,8 @@ EXPERIMENTAL {
 	rte_dev_event_monitor_stop;
 	rte_dev_iterator_init;
 	rte_dev_iterator_next;
+	rte_dev_probe;
+	rte_dev_remove;
 	rte_devargs_add;
 	rte_devargs_dump;
 	rte_devargs_insert;
