diff --git a/includes/rules.core.inc b/includes/rules.core.inc
index cbf926d..2fd66a3 100644
--- a/includes/rules.core.inc
+++ b/includes/rules.core.inc
@@ -111,7 +111,7 @@ class RulesEntityController extends EntityAPIControllerExportable {
     // Create an empty configuration, re-set basic keys and import.
     $config = rules_plugin_factory($export['PLUGIN']);
     $config->name = $name;
-    foreach (array('label', 'active', 'weight', 'tags') as $key) {
+    foreach (array('label', 'active', 'weight', 'tags', 'access_exposed') as $key) {
       if (isset($export[strtoupper($key)])) {
         $config->$key = $export[strtoupper($key)];
       }
@@ -1308,6 +1308,9 @@ abstract class RulesPlugin extends RulesExtendable {
     if ($modules = $this->dependencies()) {
       $export_cfg[$this->name]['REQUIRES'] = $modules;
     }
+    if (!empty($this->access_exposed)) {
+      $export_cfg[$this->name]['ACCESS_EXPOSED'] = $this->access_exposed;
+    };
     $export_cfg[$this->name] += $export;
     return $php ? entity_var_export($export_cfg, $prefix) : entity_var_json_export($export_cfg, $prefix);
   }
diff --git a/modules/data.rules.inc b/modules/data.rules.inc
index f97b9a0..7241e83 100644
--- a/modules/data.rules.inc
+++ b/modules/data.rules.inc
@@ -599,7 +599,8 @@ function rules_condition_data_is_form_alter(&$form, &$form_state, $options, Rule
  * Provides configuration help for the data_is condition.
  */
 function rules_condition_data_is_help() {
-  return array('#markup' => t('Compare two data values of the same type with each other.'));}
+  return array('#markup' => t('Compare two data values of the same type with each other.'));
+}
 
 /**
  * Options list callback for condition data_is.
diff --git a/modules/rules_core.rules.inc b/modules/rules_core.rules.inc
index 72c956e..7b89753 100644
--- a/modules/rules_core.rules.inc
+++ b/modules/rules_core.rules.inc
@@ -286,11 +286,19 @@ function rules_element_invoke_component_features_export(&$export, &$pipe, $modul
  * Access callback for the invoke component condition/action.
  */
 function rules_element_invoke_component_access_callback($type, $name) {
-  // Only allow access to the action/condition if the user has access to the
-  // component.
   // Cut of the leading 'component_' from the action name.
   $component = rules_config_load(substr($name, 10));
-  return $component && $component->access();
+
+  if (!$component) {
+    // Missing component.
+    return FALSE;
+  }
+  // If access is not exposed for this component, default to component access.
+  if (empty($component->access_exposed)) {
+    return $component->access();
+  }
+  // Apply the permissions.
+  return user_access('bypass rules access') || user_access("use component $component->name");
 }
 
 /**
diff --git a/rules.install b/rules.install
index 832a557..ce72c81 100644
--- a/rules.install
+++ b/rules.install
@@ -87,6 +87,13 @@ function rules_schema() {
         'length' => 255,
         'not null' => FALSE,
       ),
+      'access_exposed' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+        'description' => 'Whether to use a permission to control access for using components.',
+      ),
       'data' => array(
         'type' => 'blob',
         'size' => 'big',
@@ -413,3 +420,17 @@ function rules_update_7207() {
 function rules_update_7208() {
   // The update system is going to flush all caches anyway, so nothing to do.
 }
+
+/**
+ * Creates a flag that enables a permission for using components.
+ */
+function rules_update_7209() {
+  // Create a access exposed flag column.
+  db_add_field('rules_config', 'access_exposed', array(
+    'type' => 'int',
+    'not null' => TRUE,
+    'default' => 0,
+    'size' => 'tiny',
+    'description' => 'Whether to use a permission to control access for using components.',
+  ));
+}
diff --git a/rules.module b/rules.module
index 693284d..2a8cd28 100644
--- a/rules.module
+++ b/rules.module
@@ -995,7 +995,7 @@ function rules_theme() {
  * Implements hook_permission().
  */
 function rules_permission() {
-  return array(
+  $perms = array(
     'administer rules' => array(
       'title' => t('Administer rule configurations'),
       'description' => t('Administer rule configurations including events, conditions and actions for which the user has sufficient access permissions.'),
@@ -1009,6 +1009,30 @@ function rules_permission() {
       'title' => t('Access the Rules debug log'),
     ),
   );
+
+  // Fetch all components to generate the access keys.
+  $conditions['plugin'] = array_keys(rules_filter_array(rules_fetch_data('plugin_info'), 'component', TRUE));
+  $conditions['access_exposed'] = 1;
+  $components = entity_load('rules_config', FALSE, $conditions);
+  $perms += rules_permissions_by_component($components);
+
+  return $perms;
+}
+
+/**
+ * Helper function to get all the permissions for components that have access exposed.
+ */
+function rules_permissions_by_component(array $components = array()) {
+  $perms = array();
+  foreach ($components as $component) {
+    $perms += array(
+      "use component $component->name" => array(
+        'title' => t('Use Rules component %component', array('%component' => $component->label())),
+        'description' => t('Controls access for using the component %component via the provided action or condition. <a href="@component-edit-url">Edit this component.</a>', array('%component' => $component->label(), '@component-edit-url' => url(RulesPluginUI::path($component->name)))),
+      ),
+    );
+  }
+  return $perms;
 }
 
 /**
diff --git a/tests/rules.test b/tests/rules.test
index 59440f7..31fbf09 100644
--- a/tests/rules.test
+++ b/tests/rules.test
@@ -341,6 +341,36 @@ class RulesTestCase extends DrupalWebTestCase {
   }
 
   /**
+   * Test custom access for using component actions/conditions.
+   */
+  function testRuleComponentAccess() {
+    // Create a normal user.
+    $normal_user = $this->drupalCreateUser();
+    // Create a role for granting access to the rule component.
+    $this->normal_role = $this->drupalCreateRole(array(), 'access_rule_components');
+    $normal_user->roles[$this->normal_role] = 'access_rule_components';
+    user_save($normal_user, array('roles' => $normal_user->roles));
+    // Create an 'action set' rule component making use of a permission.
+    $action_set = rules_action_set(array('node' => array('type' => 'node')));
+    $action_set->access_exposed = TRUE;
+    $action_set->save('rules_test_roles');
+
+    // Set the global user to be the current one as access is checked for the
+    // global user.
+    global $user;
+    $user = user_load($normal_user->uid);
+    $this->assertFalse(rules_action('component_rules_test_roles')->access(), 'Authenticated user without the correct role can\'t use the rule component.');
+
+    // Assign the role that will have permissions for the rule component.
+    user_role_change_permissions($this->normal_role, array('access rules_test_roles' => 'access rules_test_roles'));
+    $this->assertTrue(rules_action('component_rules_test_roles')->access(), 'Authenticated user with the correct role can use the rule component.');
+
+    // Reset global user to anonyous.
+    $user = user_load(0);
+    $this->assertFalse(rules_action('component_rules_test_roles')->access(), 'Anonymous user can\'t use the rule component.');
+  }
+
+  /**
    * Test passing arguments by reference to an action.
    */
   function testPassingByReference() {
diff --git a/ui/rules.ui.css b/ui/rules.ui.css
index f85212c..b567051 100755
--- a/ui/rules.ui.css
+++ b/ui/rules.ui.css
@@ -183,6 +183,12 @@ ul.rules-autocomplete .ui-corner-all {
   -moz-border-radius: 0px;
 }
 
+/**
+ * Do not display the hide/show descriptions link above the permissions matrix.
+ */
+#rules-form-wrapper #edit-settings-access-permissions .compact-link {
+  display: none;
+}
 
 /* IE 6 hack for max-height. */
 * html ul.rule-autocomplete{
diff --git a/ui/ui.core.inc b/ui/ui.core.inc
index 3977dbf..70d75a9 100644
--- a/ui/ui.core.inc
+++ b/ui/ui.core.inc
@@ -488,11 +488,77 @@ class RulesPluginUI extends FacesExtender implements RulesPluginUIInterface {
         '#limit_validation_errors' => array(array('vars')),
         '#submit' => array('rules_form_submit_rebuild'),
       );
+      if (!empty($this->element->id)) {
+        // Display a setting to manage access.
+        $form['settings']['access'] = array(
+          '#weight' => 50,
+        );
+        $plugin_type = $this->element instanceof RulesActionInterface ? t('action') : t('condition');
+        $form['settings']['access']['access_exposed'] = array(
+          '#type' => 'checkbox',
+          '#title' => t('Configure access for using this component with a permission.'),
+          '#default_value' => !empty($this->element->access_exposed),
+          '#description' => t('By default, the @plugin-type for using this component may be only used by users that have access to configure the component. If checked, access is determined by a permission instead.', array('@plugin-type' => $plugin_type))
+        );
+        $form['settings']['access']['permissions'] = array(
+          '#type' => 'container',
+          '#states' => array(
+            'visible' => array(
+              ':input[name="settings[access][access_exposed]"]' => array('checked' => TRUE),
+            ),
+          ),
+        );
+        $form['settings']['access']['permissions']['matrix'] = $this->settingsFormPermissionMatrix();
+      }
     }
 
     // TODO: Attach field form thus description.
   }
 
+  /**
+   * Provides a matrix permission for the component based in the existing roles.
+   *
+   * @return
+   *   Form elements with the matrix of permissions for a component.
+   */
+  protected function settingsFormPermissionMatrix() {
+    $form['#theme'] = 'user_admin_permissions';
+    $status = array();
+    $options = array();
+
+    $role_names = user_roles();
+    $role_permissions = user_role_permissions($role_names);
+    $component_permission = rules_permissions_by_component(array($this->element));
+    $component_permission_name = key($component_permission);
+
+    $form['permission'][$component_permission_name] = array(
+      '#type' => 'item',
+      '#markup' => $component_permission[$component_permission_name]['title'],
+    );
+    $options[$component_permission_name] = '';
+    foreach ($role_names as $rid => $name) {
+      if (isset($role_permissions[$rid][$component_permission_name])) {
+        $status[$rid][] = $component_permission_name;
+      }
+    }
+
+    // Build the checkboxes for each role.
+    foreach ($role_names as $rid => $name) {
+      $form['checkboxes'][$rid] = array(
+        '#type' => 'checkboxes',
+        '#options' => $options,
+        '#default_value' => isset($status[$rid]) ? $status[$rid] : array(),
+        '#attributes' => array('class' => array('rid-' . $rid)),
+      );
+      $form['role_names'][$rid] = array('#markup' => check_plain($name), '#tree' => TRUE);
+    }
+
+    // Attach the default permissions page JavaScript.
+    $form['#attached']['js'][] = drupal_get_path('module', 'user') . '/user.permissions.js';
+
+    return $form;
+  }
+
   public function settingsFormExtractValues($form, &$form_state) {
     $form_values = RulesPluginUI::getFormStateValues($form['settings'], $form_state);
     $this->element->label = $form_values['label'];
@@ -532,6 +598,7 @@ class RulesPluginUI extends FacesExtender implements RulesPluginUIInterface {
       }
       unset($input['vars']);
     }
+    $this->element->access_exposed = isset($form_values['access']['access_exposed']) ? $form_values['access']['access_exposed'] : FALSE;
   }
 
   public function settingsFormValidate($form, &$form_state) {
@@ -542,7 +609,12 @@ class RulesPluginUI extends FacesExtender implements RulesPluginUIInterface {
   }
 
   public function settingsFormSubmit($form, &$form_state) {
-
+    if (isset($form_state['values']['settings']['access']) && !empty($this->element->access_exposed)) {
+      // Save the permission matrix.
+      foreach ($form_state['values']['settings']['access']['permissions']['matrix']['checkboxes'] as $rid => $value) {
+        user_role_change_permissions($rid, $value);
+      }
+    }
   }
 
   /**
