Make a node field read only after the node has been created
After educating myself on the Validation API, here's an example how to add the constraint to validate that the value of an entity reference field has not been changed.

Note: As pointed out by Ivan Jaros, this constraint is not validated if some module is programmatically saving entities without validating the entities first via Validation API.


Add a new constraint plugin.
    

/**
 * @file
 * Contains \Drupal\example\Plugin\Validation\Constraint\ValueNotChangedConstraint.
 */

namespace Drupal\example\Plugin\Validation\Constraint;

use Symfony\Component\Validator\Constraint;

/**
 * Constraint for checking that the value has not been changed.
 *
 * @Constraint(
 *   id = "ValueNotChanged",
 *   label = @Translation("Value has not changed", context = "Validation"),
 *   type = { "string", "entity:node" }
 * )
 */
class ValueNotChangedConstraint extends Constraint {

  /**
   * Message shown when the validation fails.
   *
   * @var string
   */
  public $message = 'Reference value can not be changed.';

}

Add validator for this constraint.
    

/**
 * @file
 * Contains \Drupal\example\Plugin\Validation\Constraint\ValueNotChangedConstraintValidator.
 */

namespace Drupal\example\Plugin\Validation\Constraint;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Violation\ConstraintViolationBuilderInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;

/**
 * Validates the ValueNotChangedConstraint.
 */
class ValueNotChangedConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {

  protected $entityTypeManager;

  /**
   * Constructor.
   *
   * @param EntityTypeManagerInterface $entity_type_manager
   *   EntityTypeManager service for loading entities.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this-&gt;entityTypeManager  = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    // Instantiates this class.
    return new static(
      // Load the service required to construct this class.
      $container-&gt;get('entity_type.manager')
    );
  }

  /**
   * Validator 2.5 and upwards compatible execution context.
   *
   * @var \Symfony\Component\Validator\Context\ExecutionContextInterface
   */
  protected $context;

  /**
   * {@inheritdoc}
   */
  public function validate($data, Constraint $constraint) {
    $violation = $this-&gt;validateValueNotChanged($data, $constraint);
    if ($violation instanceof ConstraintViolationBuilderInterface) {
      $violation-&gt;addViolation();
    }
    return;
  }

  /**
   * Validates that the value is the same than previously.
   *
   * @param EntityReferenceFieldItemListInterface $data
   *   List of referenced entities.
   * @param Constraint $constraint
   *   Our constraint.
   *
   * @return \Symfony\Component\Validator\Violation\ConstraintViolationBuilderInterface
   */
  protected function validateValueNotChanged(EntityReferenceFieldItemListInterface $data, Constraint $constraint) {
    // Get the field name of the field we're validating.
    $field_name = $data-&gt;getFieldDefinition()-&gt;get('field_name');

    // Get the entity the field belongs to.
    $parent_id = $data-&gt;getEntity()-&gt;id();

    // Entities that are about to be created don't have an ID at this point.
    // We're only interested in existing entities.
    if ($parent_id) {

      // Load the parent node from the database. The new updates are not saved
      // yet so this will be the "old" version of the entity.
      $parent = $this-&gt;entityTypeManager-&gt;getStorage('node')-&gt;load($parent_id);

      // Get the old value we want to compare against.
      $old_value = $parent-&gt;get($field_name);

      // Compare the field item lists.
      if (!$old_value-&gt;equals($data)) {
        return $this-&gt;context-&gt;buildViolation($constraint-&gt;message);
      }
    }
  }

}

Add the constraint to the desired field with hook_entity_bundle_field_info_alter(). 

/**
 * Implemeantion of hook_entity_bundle_field_info_alter().
 *
 * Adds constraint to field_example_reference field.
 */
function example_entity_bundle_field_info_alter(&amp;$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle){
  switch ($bundle) {
    case 'our_content_type':
      $fields['field_example_reference']-&gt;addConstraint('ValueNotChanged');
      break;
  }
}