diff --git a/pathauto.inc b/pathauto.inc
index 68fa0ca..92de15a 100644
--- a/pathauto.inc
+++ b/pathauto.inc
@@ -59,20 +59,15 @@ define('PATHAUTO_PUNCTUATION_DO_NOTHING', 2);
  *   A string alias.
  * @param $source
  *   A string that is the internal path.
- * @param $language
+ * @param $langcode
  *   A string indicating the path's language.
  * @return
  *   TRUE if an alias exists, FALSE if not.
+ *
+ * @deprecated Use path_pathauto_is_alias_reserved() instead.
  */
-function _pathauto_alias_exists($alias, $source, $language = LANGUAGE_NONE) {
-  $pid = db_query_range("SELECT pid FROM {url_alias} WHERE source <> :source AND alias = :alias AND language IN (:language, :language_none) ORDER BY language DESC, pid DESC", 0, 1, array(
-    ':source' => $source,
-    ':alias' => $alias,
-    ':language' => $language,
-    ':language_none' => LANGUAGE_NONE,
-  ))->fetchField();
-
-  return !empty($pid);
+function _pathauto_alias_exists($alias, $source, $langcode = LANGUAGE_NONE) {
+  return path_pathauto_is_alias_reserved();
 }
 
 /**
@@ -444,7 +439,7 @@ function pathauto_create_alias($module, $op, $source, $data, $type = NULL, $lang
  *   A string with a language code.
  */
 function pathauto_alias_uniquify(&$alias, $source, $langcode) {
-  if (!_pathauto_alias_exists($alias, $source, $langcode)) {
+  if (!pathauto_is_alias_reserved($alias, $source, $langcode)) {
     return;
   }
 
@@ -459,7 +454,7 @@ function pathauto_alias_uniquify(&$alias, $source, $langcode) {
     $unique_suffix = $separator . $i;
     $alias = truncate_utf8($original_alias, $maxlength - drupal_strlen($unique_suffix, TRUE)) . $unique_suffix;
     $i++;
-  } while (_pathauto_alias_exists($alias, $source, $langcode));
+  } while (pathauto_is_alias_reserved($alias, $source, $langcode));
 }
 
 /**
@@ -517,13 +512,6 @@ function _pathauto_path_is_callback($path) {
 function _pathauto_set_alias(array $path, $existing_alias = NULL, $op = NULL) {
   $verbose = _pathauto_verbose(NULL, $op);
 
-  // Alert users that an existing callback cannot be overridden automatically
-  if (_pathauto_path_is_callback($path['alias'])) {
-    if ($verbose) {
-      _pathauto_verbose(t('Ignoring alias %alias due to existing path conflict.', array('%alias' => $path['alias'])));
-    }
-    return;
-  }
   // Alert users if they are trying to create an alias that is the same as the internal path
   if ($path['source'] == $path['alias']) {
     if ($verbose) {
diff --git a/pathauto.module b/pathauto.module
index 4798d07..fbbdae3 100644
--- a/pathauto.module
+++ b/pathauto.module
@@ -26,9 +26,14 @@ define('PATHAUTO_IGNORE_WORDS', 'a, an, as, at, before, but, by, for, from, is,
  * Implements hook_hook_info().
  */
 function pathauto_hook_info() {
-  $info['pathauto'] = array('group' => 'pathauto');
-  $info['path_alias_types'] = array('group' => 'pathauto');
-  return $info;
+  $hooks = array(
+    'pathauto',
+    'path_alias_types',
+    'pathauto_pattern_alter',
+    'pathauto_alias_alter',
+    'pathauto_is_alias_reserved',
+  );
+  return array_fill_keys($hooks, array('group' => 'pathauto'));
 }
 
 /**
@@ -37,8 +42,7 @@ function pathauto_hook_info() {
  * Adds pathauto support for core modules.
  */
 function pathauto_module_implements_alter(&$implementations, $hook) {
-  $hooks = pathauto_hook_info();
-  if (isset($hooks[$hook])) {
+  if (in_array($hook, array('pathauto', 'path_alias_types'))) {
     $modules = array('node', 'taxonomy', 'user', 'forum', 'blog');
     foreach ($modules as $module) {
       if (module_exists($module)) {
@@ -423,6 +427,39 @@ function pathauto_entity_language($entity_type, $entity, $check_language_propert
   return !empty($langcode) ? $langcode : LANGUAGE_NONE;
 }
 
+function pathauto_is_alias_reserved($alias, $source, $langcode = LANGUAGE_NONE) {
+  foreach (module_implements('pathauto_is_alias_reserved') as $module) {
+    $result = module_invoke($module, 'pathauto_is_alias_reserved', $alias, $source, $langcode);
+    if (!empty($result)) {
+      // As soon as the first module says that an alias is in fact reserved,
+      // then there is no point in checking the rest of the modules.
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+ * Implements hook_pathauto_is_alias_reserved() on behalf of path.module.
+ */
+function path_pathauto_is_alias_reserved($alias, $source, $langcode) {
+  return (bool) db_query_range("SELECT pid FROM {url_alias} WHERE source <> :source AND alias = :alias AND language IN (:language, :language_none) ORDER BY language DESC, pid DESC", 0, 1, array(
+    ':source' => $source,
+    ':alias' => $alias,
+    ':language' => $langcode,
+    ':language_none' => LANGUAGE_NONE,
+  ))->fetchField();
+}
+
+/**
+ * Implements hook_pathauto_is_alias_reserved().
+ */
+function pathauto_pathauto_is_alias_reserved($alias, $source, $langcode) {
+  module_load_include('inc', 'pathauto');
+  return _pathauto_path_is_callback($alias);
+}
+
 if (!function_exists('path_field_extra_fields')) {
 /**
  * Implements hook_field_extra_fields() on behalf of path.module.
diff --git a/pathauto.test b/pathauto.test
index bbe2033..4bfe2b3 100644
--- a/pathauto.test
+++ b/pathauto.test
@@ -332,17 +332,17 @@ class PathautoUnitTestCase extends PathautoTestHelper {
 
     // Check that Pathauto does not create an alias of '/admin'.
     $node = $this->drupalCreateNode(array('title' => 'Admin', 'type' => 'page'));
-    $this->assertNoEntityAlias('node', $node);
+    $this->assertEntityAlias('node', $node, 'admin-0');
 
     // Check that Pathauto does not create an alias of '/modules'.
     $node->title = 'Modules';
     node_save($node);
-    $this->assertNoEntityAlias('node', $node);
+    $this->assertEntityAlias('node', $node, 'modules-0');
 
     // Check that Pathauto does not create an alias of '/index.php'.
     $node->title = 'index.php';
     node_save($node);
-    $this->assertNoEntityAlias('node', $node);
+    $this->assertEntityAlias('node', $node, 'index.php-0');
 
     // Check that a safe value gets an automatic alias. This is also a control
     // to ensure the above tests work properly.
