diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index 9a26233..62fee4d 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -661,6 +661,9 @@ function check_markup($text, $format_id = NULL, $langcode = '', $cache = FALSE,
  *     'textarea' by default.
  *   - #format: (optional) The text format ID to preselect. If NULL or not set,
  *     the default format for the current user will be used.
+ *   - #allowed_formats: (optional) An array of IDs for the text format that
+ *     the current user can select for this element. If NULL or not set, all
+ *     text formats enabled for the current user will be allowed.
  *
  * @return
  *   The expanded element.
@@ -709,14 +712,30 @@ function filter_process_format($element) {
     '#attributes' => array('class' => array('filter-wrapper')),
   );
 
-  // Get a list of formats that the current user has access to.
-  $formats = filter_formats($user);
-
   // Use the default format for this user if none was selected.
   if (!isset($element['#format'])) {
     $element['#format'] = filter_default_format($user);
   }
 
+  // Get a list of formats that the current user has access to.
+  $formats = filter_formats($user);
+
+  if (isset($element['#allowed_formats'])) {
+    // The fallback format should always be allowed.
+    $element['#allowed_formats'][] = filter_fallback_format();
+
+    // Check if the default format is in the list of allowed formats.
+    $format_allowed = in_array($element['#format'], $element['#allowed_formats']);
+
+    $formats = array_intersect_key($formats, array_flip($element['#allowed_formats']));
+  }
+  else {
+    // If formats are not restricted, we allow the current format.
+    // The current format could still be revoked if the user doesn't
+    // have the necessary permissions.
+    $format_allowed = TRUE;
+  }
+
   // If multiple text formats are available, remove the fallback. The
   // "always_show_fallback_choice" is a hidden variable that has no UI. It
   // defaults to false.
@@ -733,6 +752,7 @@ function filter_process_format($element) {
     '#attributes' => array('class' => array('filter-guidelines')),
     '#weight' => 20,
   );
+  $options = array();
   foreach ($formats as $format) {
     $options[$format->format] = $format->name;
     $element['format']['guidelines'][$format->format] = array(
@@ -766,7 +786,7 @@ function filter_process_format($element) {
 
   // If the stored format does not exist, administrators have to assign a new
   // format.
-  if (!$format_exists && $user_is_admin) {
+  if ((!$format_exists || !$format_allowed) && $user_is_admin) {
     $element['format']['format']['#required'] = TRUE;
     $element['format']['format']['#default_value'] = NULL;
     // Force access to the format selector (it may have been denied above if
@@ -778,7 +798,7 @@ function filter_process_format($element) {
   // only grants access to the filter administration, not to all formats.
   elseif (!$user_has_access || !$format_exists) {
     // Overload default values into #value to make them unalterable.
-    $element['value']['#value'] = $element['value']['#default_value'];
+    $element['value']['#value'] = isset($element['value']['#default_value']) ? $element['value']['#default_value'] : '';
     $element['format']['format']['#value'] = $element['format']['format']['#default_value'];
 
     // Prepend #pre_render callback to replace field value with user notice
diff --git a/core/modules/filter/lib/Drupal/filter/Tests/FilterFormTest.php b/core/modules/filter/lib/Drupal/filter/Tests/FilterFormTest.php
new file mode 100644
index 0000000..593aaff
--- /dev/null
+++ b/core/modules/filter/lib/Drupal/filter/Tests/FilterFormTest.php
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\FilterFormTest.
+ */
+
+namespace Drupal\filter\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+class FilterFormTest extends WebTestBase {
+
+  /**
+   * The installation profile to use with this test.
+   *
+   * @var string
+   */
+  protected $profile = 'standard';
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Filter form element',
+      'description' => 'Tests form elements with associated text formats.',
+      'group' => 'Filter',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+
+    // Create users.
+    $basic_html_format = filter_format_load('basic_html');
+    $restricted_html_format = filter_format_load('restricted_html');
+    $full_html_format = filter_format_load('full_html');
+    $this->admin_user = $this->drupalCreateUser(array(
+      'administer filters',
+      filter_permission_name($basic_html_format),
+      filter_permission_name($restricted_html_format),
+      filter_permission_name($full_html_format),
+    ));
+
+    $this->web_user = $this->drupalCreateUser(array('create page content', 'edit own page content'));
+    $this->drupalLogin($this->admin_user);
+  }
+
+  /**
+   * Tests various parameters for text fields associated with text formats.
+   */
+  function testFilterForm() {
+    $form_id = $this->randomName();
+    $form = array();
+    $form_state = form_state_defaults();
+    form_clear_error();
+    $form['op'] = array('#type' => 'submit', '#value' => t('Submit'));
+
+    $form['text_all_formats'] = array(
+      '#type' => 'text_format',
+    );
+
+    $form['text_default_formats'] = array(
+      '#type' => 'text_format',
+      '#format' => 'full_html',
+    );
+
+    $form['text_allowed_formats'] = array(
+      '#type' => 'text_format',
+      '#format' => 'full_html',
+      '#allowed_formats' => array('full_html'),
+    );
+
+    // Default format is not an allowed format.
+    $form['text_allowed_formats_no_default'] = array(
+      '#type' => 'text_format',
+      '#format' => 'basic_html',
+      '#allowed_formats' => array('full_html'),
+    );
+
+    $form['text_no_allowed_format'] = array(
+      '#type' => 'text_format',
+      '#allowed_formats' => array(),
+    );
+
+    $form_state['input']['form_id'] = $form_id;
+    $form_state['method'] = 'post';
+    drupal_prepare_form($form_id, $form, $form_state);
+    drupal_process_form($form_id, $form, $form_state);
+
+    // The fallback format is discarded, so we have one less option
+    // than there are formats.
+    $format_count = count(filter_formats()) - 1;
+    $this->assertEqual(count($form['text_all_formats']['format']['format']['#options']), $format_count, 'All text formats are available');
+
+    $this->assertEqual($form['text_default_formats']['format']['format']['#default_value'], 'full_html', 'The default format is set correctly.');
+
+    $this->assertFalse($form['text_allowed_formats']['format']['format']['#access'], 'When only one format is allowed, hide the selector.');
+
+    $this->assertNull($form['text_allowed_formats_no_default']['format']['format']['#value'], 'When default format is not allowed, for the user to choose another.');
+    $this->assertNull($form['text_no_allowed_format']['format']['format']['#value'], 'When no format is available, force the user to choose another.');
+  }
+}
