diff --git a/main/pbx.c b/main/pbx.c
index fee4191..ff970a0 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -72,6 +72,7 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/astobj2.h"
 #include "asterisk/stasis_channels.h"
 #include "asterisk/dial.h"
+#include "asterisk/vector.h"
 
 /*!
  * \note I M P O R T A N T :
@@ -1046,8 +1047,9 @@ struct ast_hint {
 
 	char context_name[AST_MAX_CONTEXT];/*!< Context of destroyed hint extension. */
 	char exten_name[AST_MAX_EXTENSION];/*!< Extension of destroyed hint extension. */
-};
 
+	AST_VECTOR(, char *) devices; /*!< Devices associated with the hint */
+};
 
 #define HINTDEVICE_DATA_LENGTH 16
 AST_THREADSTORAGE(hintdevice_data);
@@ -1077,15 +1079,28 @@ struct ast_hintdevice {
 	char hintdevice[1];
 };
 
-
 /*!
  * \note Using the device for hash
  */
 static int hintdevice_hash_cb(const void *obj, const int flags)
 {
-	const struct ast_hintdevice *ext = obj;
+	const struct ast_hintdevice *ext;
+	const char *key;
+
+	switch (flags & (OBJ_POINTER | OBJ_SEARCH_KEY | OBJ_PARTIAL_KEY)) {
+	case OBJ_SEARCH_KEY:
+		key = obj;
+		break;
+	case OBJ_POINTER:
+		ext = obj;
+		key = ext->hintdevice;
+		break;
+	default:
+		ast_assert(0);
+		return 0;
+	}
 
-	return ast_str_case_hash(ext->hintdevice);
+	return ast_str_case_hash(key);
 }
 /*!
  * \note Devices on hints are not unique so no CMP_STOP is returned
@@ -1094,29 +1109,62 @@ static int hintdevice_hash_cb(const void *obj, const int flags)
  */
 static int hintdevice_cmp_multiple(void *obj, void *arg, int flags)
 {
-	struct ast_hintdevice *ext = obj, *ext2 = arg;
+	struct ast_hintdevice *left = arg;
+	struct ast_hintdevice *right = arg;
+	const char *right_key = arg;
+	int cmp;
 
-	return !strcasecmp(ext->hintdevice, ext2->hintdevice) ? CMP_MATCH  : 0;
+	switch (flags & (OBJ_POINTER | OBJ_SEARCH_KEY | OBJ_PARTIAL_KEY)) {
+	case OBJ_POINTER:
+		right_key = right->hintdevice;
+		/* Fall through */
+	case OBJ_SEARCH_KEY:
+		cmp = strcmp(left->hintdevice, right_key);
+	break;
+	case OBJ_PARTIAL_KEY:
+		/*
+		* We could also use a partial key struct containing a length
+		* so strlen() does not get called for every comparison instead.
+		*/
+		cmp = strncmp(left->hintdevice, right_key, strlen(right_key));
+	break;
+	default:
+		/* Sort can only work on something with a full or partial key. */
+		ast_assert(0);
+		cmp = 0;
+	break;
+	}
+	return cmp ? 0 : CMP_MATCH;
 }
 
-/*
- * \details This is used with ao2_callback to remove old devices
- * when they are linked to the hint
-*/
-static int hintdevice_remove_cb(void *deviceobj, void *arg, int flags)
+static int remove_hintdevice(struct ast_hint *hint)
 {
-	struct ast_hintdevice *device = deviceobj;
-	struct ast_hint *hint = arg;
+	int i;
 
-	return (device->hint == hint) ? CMP_MATCH : 0;
-}
+	for (i = 0; i < AST_VECTOR_SIZE(&hint->devices); i++) {
+		struct ao2_iterator *dev_iter;
+		char *device = AST_VECTOR_GET(&hint->devices, i);
+
+		if (!device) {
+			continue;
+		}
+
+		dev_iter = ao2_t_callback(hintdevices, OBJ_SEARCH_KEY | OBJ_MULTIPLE,
+			hintdevice_cmp_multiple, device, "find devices in container");
+		if (dev_iter) {
+			struct ast_hintdevice *hintdevice;
+			for (; (hintdevice = ao2_iterator_next(dev_iter)); ao2_ref(hintdevice, -1)) {
+				/* Only remove those hintdevices for our hint */
+				if (hintdevice->hint == hint) {
+					ao2_unlink(hintdevices, hintdevice);
+				}
+			}
+		}
+		AST_VECTOR_REMOVE_UNORDERED(&hint->devices, i);
+		ast_free(device);
+		AST_VECTOR_INSERT(&hint->devices, i, NULL);
+	}
 
-static int remove_hintdevice(struct ast_hint *hint)
-{
-	/* iterate through all devices and remove the devices which are linked to this hint */
-	ao2_t_callback(hintdevices, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
-		hintdevice_remove_cb, hint,
-		"callback to remove all devices which are linked to a hint");
 	return 0;
 }
 
@@ -1161,13 +1209,22 @@ static int add_hintdevice(struct ast_hint *hint, const char *devicelist)
 
 	/* Spit on '&' and ',' to handle presence hints as well */
 	while ((cur = strsep(&parse, "&,"))) {
+		char *device_name;
+
 		devicelength = strlen(cur);
 		if (!devicelength) {
 			continue;
 		}
+
+		device_name = ast_strdup(cur);
+		if (!device_name) {
+			return -1;
+		}
+
 		device = ao2_t_alloc(sizeof(*device) + devicelength, hintdevice_destroy,
 			"allocating a hintdevice structure");
 		if (!device) {
+			ast_free(device_name);
 			return -1;
 		}
 		strcpy(device->hintdevice, cur);
@@ -1175,6 +1232,7 @@ static int add_hintdevice(struct ast_hint *hint, const char *devicelist)
 		device->hint = hint;
 		ao2_t_link(hintdevices, device, "Linking device into hintdevice container.");
 		ao2_t_ref(device, -1, "hintdevice is linked so we can unref");
+		AST_VECTOR_APPEND(&hint->devices, device_name);
 	}
 
 	return 0;
@@ -5697,6 +5755,7 @@ static int hint_id_cmp(void *obj, void *arg, int flags)
 static void destroy_hint(void *obj)
 {
 	struct ast_hint *hint = obj;
+	int i;
 
 	if (hint->callbacks) {
 		struct ast_state_cb *state_cb;
@@ -5726,6 +5785,12 @@ static void destroy_hint(void *obj)
 		}
 		ao2_ref(hint->callbacks, -1);
 	}
+
+	for (i = 0; i < AST_VECTOR_SIZE(&hint->devices); i++) {
+		char *device = AST_VECTOR_GET(&hint->devices, i);
+		ast_free(device);
+	}
+	AST_VECTOR_FREE(&hint->devices);
 	ast_free(hint->last_presence_subtype);
 	ast_free(hint->last_presence_message);
 }
@@ -5787,6 +5852,7 @@ static int ast_add_hint(struct ast_exten *e)
 	if (!hint_new) {
 		return -1;
 	}
+	AST_VECTOR_INIT(&hint_new->devices, 8);
 
 	/* Initialize new hint. */
 	hint_new->callbacks = ao2_container_alloc(1, NULL, hint_id_cmp);
@@ -12543,11 +12609,53 @@ static void pbx_shutdown(void)
 	pbx_builtin_clear_globals();
 }
 
+static void print_hints_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
+{
+	struct ast_hint *hint = v_obj;
+
+	if (!hint) {
+		return;
+	}
+	prnt(where, "%s@%s", ast_get_extension_name(hint->exten),
+		ast_get_context_name(ast_get_extension_context(hint->exten)));
+}
+
+static void print_hintdevices_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
+{
+	struct ast_hintdevice *hintdevice = v_obj;
+
+	if (!hintdevice) {
+		return;
+	}
+	prnt(where, "%s => %s@%s", hintdevice->hintdevice,
+		ast_get_extension_name(hintdevice->hint->exten),
+		ast_get_context_name(ast_get_extension_context(hintdevice->hint->exten)));
+}
+
+static void print_statecbs_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
+{
+	struct ast_state_cb *state_cb = v_obj;
+
+	if (!state_cb) {
+		return;
+	}
+	prnt(where, "%d", state_cb->id);
+}
+
 int ast_pbx_init(void)
 {
 	hints = ao2_container_alloc(HASH_EXTENHINT_SIZE, hint_hash, hint_cmp);
+	if (hints) {
+		ao2_container_register("hints", hints, print_hints_key);
+	}
 	hintdevices = ao2_container_alloc(HASH_EXTENHINT_SIZE, hintdevice_hash_cb, hintdevice_cmp_multiple);
+	if (hintdevices) {
+		ao2_container_register("hintdevices", hintdevices, print_hintdevices_key);
+	}
 	statecbs = ao2_container_alloc(1, NULL, statecbs_cmp);
+	if (statecbs) {
+		ao2_container_register("statecbs", statecbs, print_statecbs_key);
+	}
 
 	ast_register_cleanup(pbx_shutdown);
 
